fix: 3v3 team match wrong problems

This commit is contained in:
jakciehan
2026-05-16 09:59:54 +08:00
parent 9359139186
commit 7d17325be6
30 changed files with 441 additions and 535 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ exec > >(tee -a "$LOG") 2>&1
SERVICE_DIR="/Users/hanchengxi/workspace/tankwar_proj/content-security-service" SERVICE_DIR="/Users/hanchengxi/workspace/tankwar_proj/content-security-service"
DEPLOY_DIR="/Users/hanchengxi/workspace/tankwar_proj/deploy/content-security" DEPLOY_DIR="/Users/hanchengxi/workspace/tankwar_proj/deploy/content-security"
MASTER="root@host_172.16.16.16" 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" REMOTE_BUILD_DIR="/tmp/content-security-build"
IMAGE_NAME="content-security-service:latest" IMAGE_NAME="content-security-service:latest"
+10 -7
View File
@@ -4,8 +4,9 @@
# that run the warmcheck/nginx DaemonSet (hostNetwork hostPort 80/443). # that run the warmcheck/nginx DaemonSet (hostNetwork hostPort 80/443).
# #
# Worker public IPs (cross-VPC, so we must use public addresses): # Worker public IPs (cross-VPC, so we must use public addresses):
# - 43.138.255.42 (cvm-42 / 172.16.16.17) # - vm-0-6-opencloudos / 10.1.0.6
# - 159.75.104.221 (cvm-221 / 172.16.16.8) # - 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 # 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. # skips control-plane nodes, so it does NOT listen on :80/:443.
@@ -42,15 +43,17 @@ stream {
# ---- HTTP upstream (80) ---- # ---- HTTP upstream (80) ----
upstream k8s_http { upstream k8s_http {
# 2 workers; passive health check via max_fails/fail_timeout. # 3 workers; passive health check via max_fails/fail_timeout.
server 43.138.255.42:80 max_fails=3 fail_timeout=30s; server 10.1.0.6:80 max_fails=3 fail_timeout=30s;
server 159.75.104.221: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) ---- # ---- HTTPS upstream (443, SNI passthrough) ----
upstream k8s_https { upstream k8s_https {
server 43.138.255.42:443 max_fails=3 fail_timeout=30s; server 10.1.0.6:443 max_fails=3 fail_timeout=30s;
server 159.75.104.221: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 ---- # ---- Listeners ----
+4 -5
View File
@@ -15,8 +15,9 @@ set -euo pipefail
MASTER_HOST="${MASTER_HOST:-host_172.16.16.16}" MASTER_HOST="${MASTER_HOST:-host_172.16.16.16}"
# Intranet IPs that the MASTER uses to reach workers (no alias on the CVMs). # Intranet IPs that the MASTER uses to reach workers (no alias on the CVMs).
WORKER_INTRANET_IPS=( WORKER_INTRANET_IPS=(
"172.16.16.17" "10.1.0.6"
"172.16.16.8" "172.16.32.10"
"172.16.32.16"
) )
NAMESPACE="tankwar" NAMESPACE="tankwar"
@@ -141,12 +142,10 @@ step_verify() {
------------------------------------------------------------ ------------------------------------------------------------
Public endpoints (after DNS on www.igeek.site takes effect): 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: Direct CVM access for smoke test:
wscat -c ws://43.139.80.61:30081/ 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. Remember to allow TCP/30081 in the CVM security group.
------------------------------------------------------------ ------------------------------------------------------------
+2
View File
@@ -272,6 +272,8 @@ const NET_MSG = {
PLAYER_RESPAWN: 'player_respawn', PLAYER_RESPAWN: 'player_respawn',
TEAM_GAME_START: 'team_game_start', TEAM_GAME_START: 'team_game_start',
TEAM_GAME_OVER: 'team_game_over', TEAM_GAME_OVER: 'team_game_over',
TERRAIN_CHANGE: 'terrain_change',
BOT_STATE: 'bot_state',
RECONNECT: 'reconnect', RECONNECT: 'reconnect',
RECONNECT_OK: 'reconnect_ok', RECONNECT_OK: 'reconnect_ok',
PLAYER_DISCONNECT: 'player_disconnect', PLAYER_DISCONNECT: 'player_disconnect',
+13 -1
View File
@@ -77,12 +77,24 @@ class Bullet {
/** /**
* Render the 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 * @param {CanvasRenderingContext2D} ctx
*/ */
render(ctx) { render(ctx) {
if (!this.alive) return; 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( ctx.fillRect(
this.x - this.halfSize, this.x - this.halfSize,
this.y - this.halfSize, this.y - this.halfSize,
+1 -1
View File
@@ -45,7 +45,7 @@ class PlayerTank extends Tank {
// Skin colors (reserved for future use) // Skin colors (reserved for future use)
this._skinColors = null; this._skinColors = null;
this._skinId = 'default'; this._skinId = null;
// Fire level system // Fire level system
this.fireLevel = FIRE_LEVEL.LV1; this.fireLevel = FIRE_LEVEL.LV1;
+17
View File
@@ -307,6 +307,14 @@ class Tank {
ctx.scale(k, k); ctx.scale(k, k);
drawTankSkin(ctx, this._skinId, this._skinColors, t); drawTankSkin(ctx, this._skinId, this._skinColors, t);
ctx.restore(); 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(); ctx.restore();
return; return;
} }
@@ -344,6 +352,15 @@ class Tank {
ctx.fillRect(-hs, -hs, trackW, this.size); ctx.fillRect(-hs, -hs, trackW, this.size);
ctx.fillRect(hs - trackW, -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(); ctx.restore();
} }
+2
View File
@@ -202,6 +202,7 @@ class NetworkManager {
const profile = (typeof GameGlobal !== 'undefined') ? GameGlobal.playerProfile : null; const profile = (typeof GameGlobal !== 'undefined') ? GameGlobal.playerProfile : null;
const nickname = (profile && profile.nickname) ? profile.nickname : ''; const nickname = (profile && profile.nickname) ? profile.nickname : '';
const avatarUrl = (profile && profile.avatarUrl) ? profile.avatarUrl : ''; const avatarUrl = (profile && profile.avatarUrl) ? profile.avatarUrl : '';
const skinId = (GameGlobal && GameGlobal.skinManager) ? (GameGlobal.skinManager.getEquippedSkinId() || '') : '';
const message = JSON.stringify({ const message = JSON.stringify({
type, type,
@@ -209,6 +210,7 @@ class NetworkManager {
playerId: this._playerId, playerId: this._playerId,
nickname, nickname,
avatarUrl, avatarUrl,
skinId,
roomId: this._roomId, roomId: this._roomId,
timestamp: Date.now(), timestamp: Date.now(),
}); });
+1 -1
View File
@@ -20,7 +20,7 @@ class ShareManager {
if (wx.showShareMenu) { if (wx.showShareMenu) {
wx.showShareMenu({ wx.showShareMenu({
withShareTicket: true, withShareTicket: true,
menus: ['shareAppMessage'], menus: ['shareAppMessage', 'shareTimeline'],
}); });
} }
if (wx.onShareAppMessage) { if (wx.onShareAppMessage) {
+6 -3
View File
@@ -140,10 +140,13 @@ const GameScene = {
}); });
this._playerTank.activateShield(3000); // spawn protection 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) { if (GameGlobal.skinManager) {
this._playerTank._skinColors = GameGlobal.skinManager.getCurrentSkinColors(); const skinId = GameGlobal.skinManager.getEquippedSkinId();
this._playerTank._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 // Safety: ensure player spawn area is clear of blocking terrain
+166 -33
View File
@@ -158,6 +158,10 @@ const TeamGameScene = {
const teamAMembers = (params && params.teamA) || []; const teamAMembers = (params && params.teamA) || [];
const teamBMembers = (params && params.teamB) || []; 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'; this._myTeam = teamAMembers.find(m => m.playerId === this._myPlayerId) ? 'A' : 'B';
// Create all player tanks // Create all player tanks
@@ -165,9 +169,25 @@ const TeamGameScene = {
this._createTeamPlayers(teamAMembers, 'A', this._mapData.teamASpawns); this._createTeamPlayers(teamAMembers, 'A', this._mapData.teamASpawns);
this._createTeamPlayers(teamBMembers, 'B', this._mapData.teamBSpawns); 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 // Find local player
this._localPlayer = this._players.find(p => p.isLocal); 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 // Initialize stats
for (const p of this._players) { for (const p of this._players) {
this._stats[p.playerId] = { kills: 0, deaths: 0, assists: 0, baseDamage: 0 }; 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; tankColor = team === 'A' ? PLAYER1_COLOR : PLAYER2_COLOR;
} }
} else { } else {
// 3v3: local=gold, ally=blue, enemy=red // 3v3: Team A = blue, Team B = red
if (isLocal) { // Local player uses team color too (gold border drawn separately for identification)
tankColor = LOCAL_PLAYER_COLOR; tankColor = team === 'A' ? TEAM_A_COLOR : TEAM_B_COLOR;
} else if (isMyTeam) {
tankColor = TEAM_A_COLOR;
} else {
tankColor = TEAM_B_COLOR;
}
} }
let tank; let tank;
@@ -240,15 +255,28 @@ const TeamGameScene = {
tank.color = tankColor; tank.color = tankColor;
// Unlimited lives for 3v3 // Unlimited lives for 3v3
tank.lives = 999; tank.lives = 999;
// Apply equipped skin (only for the LOCAL player — other players keep team color) // Apply equipped skin only non-default skins override team color
if (GameGlobal.skinManager && isLocal) { if (GameGlobal.skinManager) {
tank._skinColors = GameGlobal.skinManager.getCurrentSkinColors(); const skinId = isLocal
tank._skinId = GameGlobal.skinManager.getEquippedSkinId(); ? 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); tank.activateShield(3000);
// Mark local player's tank for gold-border rendering
if (isLocal) {
tank._isLocal = true;
}
// Set initial direction based on team // Set initial direction based on team
if (team === 'A') { if (team === 'A') {
tank.direction = DIRECTION.RIGHT; tank.direction = DIRECTION.RIGHT;
@@ -321,9 +349,13 @@ const TeamGameScene = {
// Receive bullet fire from other players // Receive bullet fire from other players
unsubs.push(nm.on(NET_MSG.BULLET_FIRE, (data) => { unsubs.push(nm.on(NET_MSG.BULLET_FIRE, (data) => {
if (data.playerId && data.playerId !== this._myPlayerId) { if (!data.playerId) return;
this._spawnRemoteBullet(data); // 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 // 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; this._unsubscribers = unsubs;
}, },
@@ -558,9 +609,16 @@ const TeamGameScene = {
} else if (!player.isBot) { } else if (!player.isBot) {
// Remote player interpolation // Remote player interpolation
this._interpolateRemoteTank(player, dt); this._interpolateRemoteTank(player, dt);
} else { } else if (player.team === this._myTeam) {
// Bot AI using BotTank.updateAI // Our team's bot — we are the authority, run AI locally
this._updateBotAI(player, dt); 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); player.tank.update(dt);
@@ -673,6 +731,9 @@ const TeamGameScene = {
hp: tank.hp, hp: tank.hp,
alive: tank.alive, alive: tank.alive,
}); });
// Also sync our team's bot states
this._sendBotStates();
}, },
_sendInputIfChanged() { _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 // Collision Detection
// ============================================================ // ============================================================
@@ -738,15 +825,21 @@ const TeamGameScene = {
} }
const terrain = this._mapManager.getTerrain(row, col); 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) { 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(); bullet.destroy();
this._spawnExplosion(bullet.x, bullet.y, false); this._spawnExplosion(bullet.x, bullet.y, false);
} else if (terrain === TERRAIN.BASE_WALL) { } else if (terrain === TERRAIN.BASE_WALL) {
// Determine which team this base wall belongs to // Determine which team this base wall belongs to
const wallTeam = this._getBaseWallTeam(row, col); 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 // Friendly-fire immunity: own team's bullets don't damage own base walls
if (bulletOwner && wallTeam && bulletOwner.team === wallTeam) { if (bulletOwner && wallTeam && bulletOwner.team === wallTeam) {
@@ -754,13 +847,21 @@ const TeamGameScene = {
return; return;
} }
// Base wall has HP — use bulletHitTerrain for proper HP tracking if (isAuthority) {
this._mapManager.bulletHitTerrain(row, col, bullet.canBreakSteel); // 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(); bullet.destroy();
this._spawnExplosion(bullet.x, bullet.y, false); this._spawnExplosion(bullet.x, bullet.y, false);
} else if (terrain === TERRAIN.STEEL) { } else if (terrain === TERRAIN.STEEL) {
if (bullet.canBreakSteel) { if (bullet.canBreakSteel && isAuthority) {
this._mapManager.setTerrain(row, col, TERRAIN.EMPTY); this._mapManager.setTerrain(row, col, TERRAIN.EMPTY);
this._sendTerrainChange(row, col, TERRAIN.EMPTY);
} }
bullet.destroy(); bullet.destroy();
this._spawnExplosion(bullet.x, bullet.y, false); this._spawnExplosion(bullet.x, bullet.y, false);
@@ -836,8 +937,11 @@ const TeamGameScene = {
return; // ignore friendly base hit return; // ignore friendly base hit
} }
// Local player or local bot reports base hits to server // Local player or our team's bot reports base hits to server.
if ((bulletOwner.isLocal || bulletOwner.isBot) && this._networkManager) { // 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, { this._networkManager.send(NET_MSG.BASE_HIT, {
targetTeam, targetTeam,
damage: 1, damage: 1,
@@ -856,6 +960,13 @@ const TeamGameScene = {
const bulletOwner = this._players.find(p => p.playerId === bullet.ownerPlayerId); const bulletOwner = this._players.find(p => p.playerId === bullet.ownerPlayerId);
if (!bulletOwner) return; 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) { for (const player of this._players) {
if (!player.tank.alive || player.isRespawning) continue; if (!player.tank.alive || player.isRespawning) continue;
@@ -972,6 +1083,7 @@ const TeamGameScene = {
ownerTank: tank, ownerTank: tank,
}); });
bullet.ownerPlayerId = this._myPlayerId; bullet.ownerPlayerId = this._myPlayerId;
bullet._isAlly = true; // local player's bullets are always ally
tank.activeBullets++; tank.activeBullets++;
this._bullets.push(bullet); this._bullets.push(bullet);
GameGlobal.audioManager.playSFX('shoot'); GameGlobal.audioManager.playSFX('shoot');
@@ -1003,8 +1115,20 @@ const TeamGameScene = {
ownerTank: tank, ownerTank: tank,
}); });
bullet.ownerPlayerId = player.playerId; bullet.ownerPlayerId = player.playerId;
bullet._isAlly = player.team === this._myTeam; // bot on my team = ally
tank.activeBullets++; tank.activeBullets++;
this._bullets.push(bullet); 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) { _spawnRemoteBullet(data) {
@@ -1031,6 +1155,7 @@ const TeamGameScene = {
ownerTank: player.tank, ownerTank: player.tank,
}); });
bullet.ownerPlayerId = data.playerId; bullet.ownerPlayerId = data.playerId;
bullet._isAlly = player.team === this._myTeam; // remote on my team = ally
player.tank.activeBullets++; player.tank.activeBullets++;
this._bullets.push(bullet); this._bullets.push(bullet);
}, },
@@ -1070,8 +1195,11 @@ const TeamGameScene = {
// Start respawn timer // Start respawn timer
this._startRespawn(victim); this._startRespawn(victim);
// If local player or local bot killed someone, notify server // If local player or our team's bot killed someone, notify server.
if ((killer.isLocal || killer.isBot) && this._networkManager) { // 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, { this._networkManager.send(NET_MSG.PLAYER_KILLED, {
killerId: killer.playerId, killerId: killer.playerId,
victimId: victim.playerId, victimId: victim.playerId,
@@ -1191,12 +1319,11 @@ const TeamGameScene = {
// Per-tank team color: // Per-tank team color:
// - local player → gold // - local player → gold
// - ally (not me) → blue // - Team A (ally or enemy) → blue
// - enemy → red // - Team B (ally or enemy) → red
let labelColor; let labelColor;
if (player.isLocal) labelColor = LOCAL_PLAYER_COLOR; if (player.isLocal) labelColor = LOCAL_PLAYER_COLOR;
else if (player.team === this._myTeam) labelColor = TEAM_A_COLOR; else labelColor = player.team === 'A' ? TEAM_A_COLOR : TEAM_B_COLOR;
else labelColor = TEAM_B_COLOR;
ctx.fillStyle = labelColor; ctx.fillStyle = labelColor;
ctx.textAlign = 'center'; ctx.textAlign = 'center';
@@ -1289,15 +1416,21 @@ const TeamGameScene = {
if (profile && profile.nickname) raw = profile.nickname; if (profile && profile.nickname) raw = profile.nickname;
else raw = player.nickname || ''; else raw = player.nickname || '';
} else { } 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 || ''; raw = player.nickname || '';
} }
if (!raw) { if (!raw) {
if (player.isBot) { if (player.isBot) {
raw = ''; // bot — we already draw the 🤖 marker, skip name raw = ''; // bot — we already draw the 🤖 marker, skip name
} else if (profile && typeof profile.getDisplayName === 'function') { } else if (player.playerId && typeof player.playerId === 'string') {
raw = profile.getDisplayName(player.playerId); // Derive a stable anonymous tag from the remote player's own ID.
const tail = player.playerId.slice(-4).toUpperCase();
raw = `Tanker_${tail}`;
} else { } else {
raw = player.playerId || ''; raw = '';
} }
} }
if (!raw) return ''; if (!raw) return '';
+2
View File
@@ -360,6 +360,8 @@ const TeamRoomScene = {
teamB: data.teamB, teamB: data.teamB,
teamABaseHp: data.teamABaseHp, teamABaseHp: data.teamABaseHp,
teamBBaseHp: data.teamBBaseHp, teamBBaseHp: data.teamBBaseHp,
battleMode: data.battleMode || '3v3',
roomId: data.roomId || '',
myPlayerId: this._myPlayerId, myPlayerId: this._myPlayerId,
}); });
}, },
-1
View File
@@ -1,4 +1,3 @@
node_modules
npm-debug.log npm-debug.log
.DS_Store .DS_Store
.git .git
+5 -4
View File
@@ -6,10 +6,11 @@
## 集群信息 ## 集群信息
目标K8s集群由以下3台CVM组成: 目标K8s集群由以下4台CVM组成:
- 43.139.80.61 (host_172.16.16.16) - 43.139.80.61 (host_172.16.16.16) — Master
- 43.138.255.42 (host_172.16.16.17) - 10.1.0.6 (vm-0-6-opencloudos) — Worker
- 159.75.104.221 (host_172.16.16.8) - 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` SSH连接:`ssh root@host_172.16.16.16`
+3 -9
View File
@@ -5,12 +5,8 @@ LABEL maintainer="tankwar" \
WORKDIR /app WORKDIR /app
# Install dependencies first (leverage Docker layer cache) # Copy all source including node_modules (pre-installed locally)
COPY package.json package-lock.json* ./ # This avoids npm install issues due to network restrictions on build nodes
RUN npm install --omit=dev --no-audit --no-fund \
&& npm cache clean --force
# Copy the rest of the source
COPY . . COPY . .
ENV NODE_ENV=production \ ENV NODE_ENV=production \
@@ -19,7 +15,5 @@ ENV NODE_ENV=production \
EXPOSE 3000 EXPOSE 3000
# Graceful shutdown & init for PID 1 # Use node directly (tini unavailable due to network restrictions on nodes)
RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "index.js"] CMD ["node", "index.js"]
+87 -31
View File
@@ -146,6 +146,8 @@ const NET_MSG = {
PLAYER_RESPAWN: 'player_respawn', PLAYER_RESPAWN: 'player_respawn',
TEAM_GAME_START: 'team_game_start', TEAM_GAME_START: 'team_game_start',
TEAM_GAME_OVER: 'team_game_over', TEAM_GAME_OVER: 'team_game_over',
TERRAIN_CHANGE: 'terrain_change',
BOT_STATE: 'bot_state',
RECONNECT: 'reconnect', RECONNECT: 'reconnect',
RECONNECT_OK: 'reconnect_ok', RECONNECT_OK: 'reconnect_ok',
PLAYER_DISCONNECT: 'player_disconnect', PLAYER_DISCONNECT: 'player_disconnect',
@@ -230,6 +232,7 @@ class PlayerInfo {
this.playerId = playerId; this.playerId = playerId;
this.nickname = ''; this.nickname = '';
this.avatarUrl = ''; this.avatarUrl = '';
this.skinId = ''; // equipped tank skin id
this.roomId = null; this.roomId = null;
this.teamId = null; this.teamId = null;
this.isAlive = true; this.isAlive = true;
@@ -249,7 +252,7 @@ class TeamRoom {
* @param {string} [battleMode='3v3'] - Battle mode ('1v1' or '3v3') * @param {string} [battleMode='3v3'] - Battle mode ('1v1' or '3v3')
* @param {string} [leaderNickname=''] - Display nickname of the leader * @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.id = id;
this.state = 'forming'; // forming | matching | playing | finished this.state = 'forming'; // forming | matching | playing | finished
this.createdAt = Date.now(); this.createdAt = Date.now();
@@ -260,8 +263,8 @@ class TeamRoom {
this.teamSize = config.teamSize; this.teamSize = config.teamSize;
this.fillWithBotsEnabled = config.fillWithBots; this.fillWithBotsEnabled = config.fillWithBots;
// Team A members: { ws, playerId, nickname, avatarUrl, ready, isBot, disconnectedAt } // Team A members: { ws, playerId, nickname, avatarUrl, skinId, ready, isBot, disconnectedAt }
this.teamA = [{ ws: leaderWs, playerId: leaderId, nickname: leaderNickname || '', avatarUrl: leaderAvatarUrl || '', ready: true, isBot: false, disconnectedAt: null }]; this.teamA = [{ ws: leaderWs, playerId: leaderId, nickname: leaderNickname || '', avatarUrl: leaderAvatarUrl || '', skinId: leaderSkinId || '', ready: true, isBot: false, disconnectedAt: null }];
// Team B members // Team B members
this.teamB = []; this.teamB = [];
this.leaderId = leaderId; this.leaderId = leaderId;
@@ -329,15 +332,19 @@ class TeamRoom {
} }
/** Add a player to team A */ /** 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; 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; return true;
} }
addToTeamB(ws, playerId, nickname = '', avatarUrl = '') { addToTeamB(ws, playerId, nickname = '', avatarUrl = '', skinId = '') {
if (this.teamB.length >= this.teamSize) return false; 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; return true;
} }
/** Remove a player from the team room */ /** Remove a player from the team room */
@@ -435,6 +442,7 @@ class TeamRoom {
playerId: m.playerId, playerId: m.playerId,
nickname: m.nickname || '', nickname: m.nickname || '',
avatarUrl: m.avatarUrl || '', avatarUrl: m.avatarUrl || '',
skinId: m.skinId || '',
ready: m.ready, ready: m.ready,
isBot: m.isBot, isBot: m.isBot,
isLeader: m.playerId === this.leaderId, isLeader: m.playerId === this.leaderId,
@@ -444,6 +452,7 @@ class TeamRoom {
playerId: m.playerId, playerId: m.playerId,
nickname: m.nickname || '', nickname: m.nickname || '',
avatarUrl: m.avatarUrl || '', avatarUrl: m.avatarUrl || '',
skinId: m.skinId || '',
ready: m.ready, ready: m.ready,
isBot: m.isBot, isBot: m.isBot,
connected: m.isBot || (m.ws && m.ws.readyState === 1), connected: m.isBot || (m.ws && m.ws.readyState === 1),
@@ -551,7 +560,7 @@ function handleCreateRoom(ws, data) {
const roomCode = generateRoomCode(); const roomCode = generateRoomCode();
// Create a TeamRoom in 1v1 mode instead of a legacy Room // 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); teamRooms.set(roomCode, teamRoom);
playerInfo.teamId = roomCode; playerInfo.teamId = roomCode;
@@ -600,7 +609,7 @@ function handleJoinRoom(ws, data) {
} }
// Join as team B // 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; playerInfo.teamId = roomId;
console.log(`[Server] Player ${playerInfo.playerId} joined 1v1 room ${roomId} (TeamRoom)`); console.log(`[Server] Player ${playerInfo.playerId} joined 1v1 room ${roomId} (TeamRoom)`);
@@ -670,7 +679,7 @@ function handleCreateTeam(ws, data) {
} }
const teamId = generateTeamId(); 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); teamRooms.set(teamId, teamRoom);
playerInfo.teamId = teamId; playerInfo.teamId = teamId;
@@ -694,7 +703,7 @@ function handleJoinTeam(ws, data) {
// Team was cleaned up (e.g. leader disconnected during dev-tool reload). // 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. // 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}`); 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); teamRooms.set(teamId, teamRoom);
playerInfo.teamId = teamId; playerInfo.teamId = teamId;
sendMessage(ws, NET_MSG.TEAM_STATE, teamRoom.getTeamState()); sendMessage(ws, NET_MSG.TEAM_STATE, teamRoom.getTeamState());
@@ -716,7 +725,7 @@ function handleJoinTeam(ws, data) {
handleLeaveTeam(ws, {}); 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; playerInfo.teamId = teamId;
console.log(`[Server] Player ${playerInfo.playerId} joined team ${teamId}`); console.log(`[Server] Player ${playerInfo.playerId} joined team ${teamId}`);
@@ -874,8 +883,10 @@ function handleMatchStart(ws, data) {
teamRoom.state = 'matching'; teamRoom.state = 'matching';
teamRoom.matchStartTime = Date.now(); teamRoom.matchStartTime = Date.now();
// Add to match pool // Add to match pool (dedup guard)
teamMatchPool.push(teamRoom); if (!teamMatchPool.includes(teamRoom)) {
teamMatchPool.push(teamRoom);
}
console.log(`[Server] Team ${teamRoom.id} entered matching pool`); 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 // Create a solo team room for this player
const teamId = generateTeamId(); 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.state = 'matching';
teamRoom.matchStartTime = Date.now(); teamRoom.matchStartTime = Date.now();
teamRooms.set(teamId, teamRoom); teamRooms.set(teamId, teamRoom);
playerInfo.teamId = teamId; playerInfo.teamId = teamId;
// Add to solo match pool // Add to solo match pool (dedup guard)
soloMatchPool.push(ws); if (!soloMatchPool.includes(ws)) {
soloMatchPool.push(ws);
}
console.log(`[Server] Player ${playerInfo.playerId} entered solo match pool (team ${teamId})`); console.log(`[Server] Player ${playerInfo.playerId} entered solo match pool (team ${teamId})`);
@@ -988,9 +1001,11 @@ function tryMatchTeams() {
const teamA_room = teamMatchPool.shift(); const teamA_room = teamMatchPool.shift();
const teamB_room = teamMatchPool.shift(); const teamB_room = teamMatchPool.shift();
// Merge team B members into team A room as opponents // Merge team B room members into team A room as opponents
for (const member of teamB_room.teamA) { // Both teamA and teamB of teamB_room should be moved
teamA_room.addToTeamB(member.ws, member.playerId, member.nickname || '', member.avatarUrl || ''); 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) { if (member.ws) {
const info = players.get(member.ws); const info = players.get(member.ws);
if (info) info.teamId = teamA_room.id; if (info) info.teamId = teamA_room.id;
@@ -1019,8 +1034,15 @@ function tryMatchTeams() {
}); });
if (availableSolos.length >= 2) { if (availableSolos.length >= 2) {
// Take up to 10 solo players and form a game // Deduplicate by playerId — same player should not appear twice
const gamePlayers = availableSolos.splice(0, Math.min(10, availableSolos.length)); 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 // Remove from solo pool
for (const ws of gamePlayers) { for (const ws of gamePlayers) {
@@ -1053,11 +1075,17 @@ function tryMatchTeams() {
info.teamId = gameRoom.id; info.teamId = gameRoom.id;
// Alternate: odd index -> team A, even index -> team B // Alternate teams: first remaining player → teamB, next → teamA, etc.
if (i % 2 === 1 && !gameRoom.isTeamAFull()) { // (player at index 0 is already in teamA as the room creator)
gameRoom.addToTeamA(ws, info.playerId, info.nickname || '', info.avatarUrl || ''); 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 { } 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 = { const gameData = {
mapId: teamRoom.mapId, mapId: teamRoom.mapId,
teamA: teamRoom.teamA.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 })), teamB: teamRoom.teamB.map(m => ({ playerId: m.playerId, nickname: m.nickname || '', isBot: m.isBot, skinId: m.skinId || '' })),
teamABaseHp: teamRoom.teamABaseHp, teamABaseHp: teamRoom.teamABaseHp,
teamBBaseHp: teamRoom.teamBBaseHp, teamBBaseHp: teamRoom.teamBBaseHp,
battleMode: teamRoom.battleMode, battleMode: teamRoom.battleMode,
@@ -1097,6 +1125,8 @@ function startTeamGame(teamRoom) {
}; };
console.log(`[Server] ${teamRoom.battleMode} game starting in room ${teamRoom.id}`); 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 1v1, use GAME_START message (client RoomScene listens for it)
// For 3v3, use TEAM_GAME_START message (client TeamRoomScene listens for it) // For 3v3, use TEAM_GAME_START message (client TeamRoomScene listens for it)
@@ -1408,7 +1438,7 @@ function handleMessage(ws, rawData) {
return; return;
} }
const { type, data, playerId, nickname, avatarUrl } = msg; const { type, data, playerId, nickname, avatarUrl, skinId } = msg;
// Update player info // Update player info
const playerInfo = players.get(ws); 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) { switch (type) {
@@ -1469,15 +1513,27 @@ function handleMessage(ws, rawData) {
// Relay gameplay messages // Relay gameplay messages
case NET_MSG.PLAYER_INPUT: 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.PLAYER_STATE:
case NET_MSG.BULLET_FIRE: case NET_MSG.BULLET_FIRE:
case NET_MSG.BULLET_HIT: case NET_MSG.BULLET_HIT:
case NET_MSG.PLAYER_HIT: case NET_MSG.PLAYER_HIT:
case NET_MSG.PLAYER_KILLED: case NET_MSG.PLAYER_KILLED:
case NET_MSG.GAME_OVER: 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) { if (playerInfo && playerInfo.teamId) {
relayToTeamRoom(ws, type, { ...data, playerId: playerInfo.playerId }); relayToTeamRoom(ws, type, data || {});
} else if (playerInfo && playerInfo.roomId) { } else if (playerInfo && playerInfo.roomId) {
relayToOpponent(ws, type, data || {}); relayToOpponent(ws, type, data || {});
} }
+2 -2
View File
@@ -14,7 +14,7 @@ metadata:
labels: labels:
app: tankwar-server app: tankwar-server
spec: spec:
replicas: 3 replicas: 1
selector: selector:
matchLabels: matchLabels:
app: tankwar-server app: tankwar-server
@@ -78,7 +78,7 @@ metadata:
labels: labels:
app: tankwar-server app: tankwar-server
spec: spec:
replicas: 3 replicas: 1
selector: selector:
matchLabels: matchLabels:
app: tankwar-server app: tankwar-server
+36 -165
View File
@@ -6,8 +6,6 @@
"packages": { "packages": {
"node_modules/accepts": { "node_modules/accepts": {
"version": "2.0.0", "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", "license": "MIT",
"dependencies": { "dependencies": {
"mime-types": "^3.0.0", "mime-types": "^3.0.0",
@@ -19,14 +17,10 @@
}, },
"node_modules/append-field": { "node_modules/append-field": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://mirrors.tencent.com/npm/append-field/-/append-field-1.0.0.tgz",
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/body-parser": { "node_modules/body-parser": {
"version": "2.2.2", "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", "license": "MIT",
"dependencies": { "dependencies": {
"bytes": "^3.1.2", "bytes": "^3.1.2",
@@ -49,14 +43,10 @@
}, },
"node_modules/buffer-from": { "node_modules/buffer-from": {
"version": "1.1.2", "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" "license": "MIT"
}, },
"node_modules/busboy": { "node_modules/busboy": {
"version": "1.6.0", "version": "1.6.0",
"resolved": "https://mirrors.tencent.com/npm/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"dependencies": { "dependencies": {
"streamsearch": "^1.1.0" "streamsearch": "^1.1.0"
}, },
@@ -66,8 +56,6 @@
}, },
"node_modules/bytes": { "node_modules/bytes": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://mirrors.tencent.com/npm/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@@ -75,8 +63,7 @@
}, },
"node_modules/call-bind-apply-helpers": { "node_modules/call-bind-apply-helpers": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://mirrors.tencent.com/npm/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "license": "MIT",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dependencies": { "dependencies": {
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
"function-bind": "^1.1.2" "function-bind": "^1.1.2"
@@ -87,8 +74,6 @@
}, },
"node_modules/call-bound": { "node_modules/call-bound": {
"version": "1.0.4", "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", "license": "MIT",
"dependencies": { "dependencies": {
"call-bind-apply-helpers": "^1.0.2", "call-bind-apply-helpers": "^1.0.2",
@@ -103,11 +88,10 @@
}, },
"node_modules/concat-stream": { "node_modules/concat-stream": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://mirrors.tencent.com/npm/concat-stream/-/concat-stream-2.0.0.tgz",
"integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
"engines": [ "engines": [
"node >= 6.0" "node >= 6.0"
], ],
"license": "MIT",
"dependencies": { "dependencies": {
"buffer-from": "^1.0.0", "buffer-from": "^1.0.0",
"inherits": "^2.0.3", "inherits": "^2.0.3",
@@ -117,8 +101,6 @@
}, },
"node_modules/content-disposition": { "node_modules/content-disposition": {
"version": "1.1.0", "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", "license": "MIT",
"engines": { "engines": {
"node": ">=18" "node": ">=18"
@@ -130,16 +112,13 @@
}, },
"node_modules/content-type": { "node_modules/content-type": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://mirrors.tencent.com/npm/content-type/-/content-type-1.0.5.tgz", "license": "MIT",
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/cookie": { "node_modules/cookie": {
"version": "0.7.2", "version": "0.7.2",
"resolved": "https://mirrors.tencent.com/npm/cookie/-/cookie-0.7.2.tgz",
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -147,8 +126,6 @@
}, },
"node_modules/cookie-signature": { "node_modules/cookie-signature": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://mirrors.tencent.com/npm/cookie-signature/-/cookie-signature-1.2.2.tgz",
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.6.0" "node": ">=6.6.0"
@@ -156,8 +133,6 @@
}, },
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.3", "version": "4.4.3",
"resolved": "https://mirrors.tencent.com/npm/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ms": "^2.1.3" "ms": "^2.1.3"
@@ -173,8 +148,6 @@
}, },
"node_modules/depd": { "node_modules/depd": {
"version": "2.0.0", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@@ -182,8 +155,6 @@
}, },
"node_modules/dunder-proto": { "node_modules/dunder-proto": {
"version": "1.0.1", "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", "license": "MIT",
"dependencies": { "dependencies": {
"call-bind-apply-helpers": "^1.0.1", "call-bind-apply-helpers": "^1.0.1",
@@ -196,13 +167,10 @@
}, },
"node_modules/ee-first": { "node_modules/ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://mirrors.tencent.com/npm/ee-first/-/ee-first-1.1.1.tgz", "license": "MIT"
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
}, },
"node_modules/encodeurl": { "node_modules/encodeurl": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://mirrors.tencent.com/npm/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@@ -210,8 +178,6 @@
}, },
"node_modules/es-define-property": { "node_modules/es-define-property": {
"version": "1.0.1", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@@ -219,16 +185,14 @@
}, },
"node_modules/es-errors": { "node_modules/es-errors": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://mirrors.tencent.com/npm/es-errors/-/es-errors-1.3.0.tgz", "license": "MIT",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/es-object-atoms": { "node_modules/es-object-atoms": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://mirrors.tencent.com/npm/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "license": "MIT",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"dependencies": { "dependencies": {
"es-errors": "^1.3.0" "es-errors": "^1.3.0"
}, },
@@ -238,13 +202,10 @@
}, },
"node_modules/escape-html": { "node_modules/escape-html": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://mirrors.tencent.com/npm/escape-html/-/escape-html-1.0.3.tgz", "license": "MIT"
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
}, },
"node_modules/etag": { "node_modules/etag": {
"version": "1.8.1", "version": "1.8.1",
"resolved": "https://mirrors.tencent.com/npm/etag/-/etag-1.8.1.tgz",
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -252,8 +213,6 @@
}, },
"node_modules/express": { "node_modules/express": {
"version": "5.2.1", "version": "5.2.1",
"resolved": "https://mirrors.tencent.com/npm/express/-/express-5.2.1.tgz",
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"accepts": "^2.0.0", "accepts": "^2.0.0",
@@ -295,8 +254,6 @@
}, },
"node_modules/finalhandler": { "node_modules/finalhandler": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://mirrors.tencent.com/npm/finalhandler/-/finalhandler-2.1.1.tgz",
"integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"debug": "^4.4.0", "debug": "^4.4.0",
@@ -316,8 +273,6 @@
}, },
"node_modules/forwarded": { "node_modules/forwarded": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://mirrors.tencent.com/npm/forwarded/-/forwarded-0.2.0.tgz",
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -325,16 +280,13 @@
}, },
"node_modules/fresh": { "node_modules/fresh": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://mirrors.tencent.com/npm/fresh/-/fresh-2.0.0.tgz", "license": "MIT",
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/function-bind": { "node_modules/function-bind": {
"version": "1.1.2", "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", "license": "MIT",
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
@@ -342,8 +294,7 @@
}, },
"node_modules/get-intrinsic": { "node_modules/get-intrinsic": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://mirrors.tencent.com/npm/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "license": "MIT",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dependencies": { "dependencies": {
"call-bind-apply-helpers": "^1.0.2", "call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1", "es-define-property": "^1.0.1",
@@ -365,8 +316,6 @@
}, },
"node_modules/get-proto": { "node_modules/get-proto": {
"version": "1.0.1", "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", "license": "MIT",
"dependencies": { "dependencies": {
"dunder-proto": "^1.0.1", "dunder-proto": "^1.0.1",
@@ -378,8 +327,7 @@
}, },
"node_modules/gopd": { "node_modules/gopd": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://mirrors.tencent.com/npm/gopd/-/gopd-1.2.0.tgz", "license": "MIT",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
}, },
@@ -389,8 +337,7 @@
}, },
"node_modules/has-symbols": { "node_modules/has-symbols": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://mirrors.tencent.com/npm/has-symbols/-/has-symbols-1.1.0.tgz", "license": "MIT",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
}, },
@@ -400,8 +347,7 @@
}, },
"node_modules/hasown": { "node_modules/hasown": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://mirrors.tencent.com/npm/hasown/-/hasown-2.0.3.tgz", "license": "MIT",
"integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
"dependencies": { "dependencies": {
"function-bind": "^1.1.2" "function-bind": "^1.1.2"
}, },
@@ -411,8 +357,7 @@
}, },
"node_modules/http-errors": { "node_modules/http-errors": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://mirrors.tencent.com/npm/http-errors/-/http-errors-2.0.1.tgz", "license": "MIT",
"integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
"dependencies": { "dependencies": {
"depd": "~2.0.0", "depd": "~2.0.0",
"inherits": "~2.0.4", "inherits": "~2.0.4",
@@ -430,8 +375,6 @@
}, },
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.7.2", "version": "0.7.2",
"resolved": "https://mirrors.tencent.com/npm/iconv-lite/-/iconv-lite-0.7.2.tgz",
"integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0" "safer-buffer": ">= 2.1.2 < 3.0.0"
@@ -446,14 +389,10 @@
}, },
"node_modules/inherits": { "node_modules/inherits": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://mirrors.tencent.com/npm/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/ipaddr.js": { "node_modules/ipaddr.js": {
"version": "1.9.1", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.10" "node": ">= 0.10"
@@ -461,14 +400,10 @@
}, },
"node_modules/is-promise": { "node_modules/is-promise": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://mirrors.tencent.com/npm/is-promise/-/is-promise-4.0.0.tgz",
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/math-intrinsics": { "node_modules/math-intrinsics": {
"version": "1.1.0", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@@ -476,8 +411,6 @@
}, },
"node_modules/media-typer": { "node_modules/media-typer": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://mirrors.tencent.com/npm/media-typer/-/media-typer-1.1.0.tgz",
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@@ -485,8 +418,6 @@
}, },
"node_modules/merge-descriptors": { "node_modules/merge-descriptors": {
"version": "2.0.0", "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", "license": "MIT",
"engines": { "engines": {
"node": ">=18" "node": ">=18"
@@ -497,8 +428,6 @@
}, },
"node_modules/mime-db": { "node_modules/mime-db": {
"version": "1.54.0", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -506,8 +435,7 @@
}, },
"node_modules/mime-types": { "node_modules/mime-types": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://mirrors.tencent.com/npm/mime-types/-/mime-types-3.0.2.tgz", "license": "MIT",
"integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
"dependencies": { "dependencies": {
"mime-db": "^1.54.0" "mime-db": "^1.54.0"
}, },
@@ -521,13 +449,10 @@
}, },
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://mirrors.tencent.com/npm/ms/-/ms-2.1.3.tgz", "license": "MIT"
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
}, },
"node_modules/multer": { "node_modules/multer": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://mirrors.tencent.com/npm/multer/-/multer-2.1.1.tgz",
"integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"append-field": "^1.0.0", "append-field": "^1.0.0",
@@ -545,8 +470,6 @@
}, },
"node_modules/multer/node_modules/media-typer": { "node_modules/multer/node_modules/media-typer": {
"version": "0.3.0", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -554,8 +477,6 @@
}, },
"node_modules/multer/node_modules/mime-db": { "node_modules/multer/node_modules/mime-db": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://mirrors.tencent.com/npm/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -563,8 +484,7 @@
}, },
"node_modules/multer/node_modules/mime-types": { "node_modules/multer/node_modules/mime-types": {
"version": "2.1.35", "version": "2.1.35",
"resolved": "https://mirrors.tencent.com/npm/mime-types/-/mime-types-2.1.35.tgz", "license": "MIT",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": { "dependencies": {
"mime-db": "1.52.0" "mime-db": "1.52.0"
}, },
@@ -574,8 +494,7 @@
}, },
"node_modules/multer/node_modules/type-is": { "node_modules/multer/node_modules/type-is": {
"version": "1.6.18", "version": "1.6.18",
"resolved": "https://mirrors.tencent.com/npm/type-is/-/type-is-1.6.18.tgz", "license": "MIT",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"dependencies": { "dependencies": {
"media-typer": "0.3.0", "media-typer": "0.3.0",
"mime-types": "~2.1.24" "mime-types": "~2.1.24"
@@ -586,8 +505,6 @@
}, },
"node_modules/negotiator": { "node_modules/negotiator": {
"version": "1.0.0", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -595,8 +512,6 @@
}, },
"node_modules/object-inspect": { "node_modules/object-inspect": {
"version": "1.13.4", "version": "1.13.4",
"resolved": "https://mirrors.tencent.com/npm/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@@ -607,8 +522,7 @@
}, },
"node_modules/on-finished": { "node_modules/on-finished": {
"version": "2.4.1", "version": "2.4.1",
"resolved": "https://mirrors.tencent.com/npm/on-finished/-/on-finished-2.4.1.tgz", "license": "MIT",
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"dependencies": { "dependencies": {
"ee-first": "1.1.1" "ee-first": "1.1.1"
}, },
@@ -618,24 +532,21 @@
}, },
"node_modules/once": { "node_modules/once": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://mirrors.tencent.com/npm/once/-/once-1.4.0.tgz", "license": "ISC",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dependencies": { "dependencies": {
"wrappy": "1" "wrappy": "1"
} }
}, },
"node_modules/parseurl": { "node_modules/parseurl": {
"version": "1.3.3", "version": "1.3.3",
"resolved": "https://mirrors.tencent.com/npm/parseurl/-/parseurl-1.3.3.tgz", "license": "MIT",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/path-to-regexp": { "node_modules/path-to-regexp": {
"version": "8.4.2", "version": "8.4.2",
"resolved": "https://mirrors.tencent.com/npm/path-to-regexp/-/path-to-regexp-8.4.2.tgz", "license": "MIT",
"integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==",
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/express" "url": "https://opencollective.com/express"
@@ -643,8 +554,6 @@
}, },
"node_modules/proxy-addr": { "node_modules/proxy-addr": {
"version": "2.0.7", "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", "license": "MIT",
"dependencies": { "dependencies": {
"forwarded": "0.2.0", "forwarded": "0.2.0",
@@ -656,8 +565,6 @@
}, },
"node_modules/qs": { "node_modules/qs": {
"version": "6.15.1", "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", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"side-channel": "^1.1.0" "side-channel": "^1.1.0"
@@ -671,8 +578,6 @@
}, },
"node_modules/range-parser": { "node_modules/range-parser": {
"version": "1.2.1", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -680,8 +585,7 @@
}, },
"node_modules/raw-body": { "node_modules/raw-body": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://mirrors.tencent.com/npm/raw-body/-/raw-body-3.0.2.tgz", "license": "MIT",
"integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
"dependencies": { "dependencies": {
"bytes": "~3.1.2", "bytes": "~3.1.2",
"http-errors": "~2.0.1", "http-errors": "~2.0.1",
@@ -694,8 +598,7 @@
}, },
"node_modules/readable-stream": { "node_modules/readable-stream": {
"version": "3.6.2", "version": "3.6.2",
"resolved": "https://mirrors.tencent.com/npm/readable-stream/-/readable-stream-3.6.2.tgz", "license": "MIT",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dependencies": { "dependencies": {
"inherits": "^2.0.3", "inherits": "^2.0.3",
"string_decoder": "^1.1.1", "string_decoder": "^1.1.1",
@@ -707,8 +610,6 @@
}, },
"node_modules/router": { "node_modules/router": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://mirrors.tencent.com/npm/router/-/router-2.2.0.tgz",
"integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"debug": "^4.4.0", "debug": "^4.4.0",
@@ -723,8 +624,6 @@
}, },
"node_modules/safe-buffer": { "node_modules/safe-buffer": {
"version": "5.2.1", "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": [ "funding": [
{ {
"type": "github", "type": "github",
@@ -738,17 +637,16 @@
"type": "consulting", "type": "consulting",
"url": "https://feross.org/support" "url": "https://feross.org/support"
} }
] ],
"license": "MIT"
}, },
"node_modules/safer-buffer": { "node_modules/safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://mirrors.tencent.com/npm/safer-buffer/-/safer-buffer-2.1.2.tgz", "license": "MIT"
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"node_modules/send": { "node_modules/send": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://mirrors.tencent.com/npm/send/-/send-1.2.1.tgz", "license": "MIT",
"integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
"dependencies": { "dependencies": {
"debug": "^4.4.3", "debug": "^4.4.3",
"encodeurl": "^2.0.0", "encodeurl": "^2.0.0",
@@ -772,8 +670,6 @@
}, },
"node_modules/serve-static": { "node_modules/serve-static": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://mirrors.tencent.com/npm/serve-static/-/serve-static-2.2.1.tgz",
"integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"encodeurl": "^2.0.0", "encodeurl": "^2.0.0",
@@ -791,13 +687,11 @@
}, },
"node_modules/setprototypeof": { "node_modules/setprototypeof": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://mirrors.tencent.com/npm/setprototypeof/-/setprototypeof-1.2.0.tgz", "license": "ISC"
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
}, },
"node_modules/side-channel": { "node_modules/side-channel": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://mirrors.tencent.com/npm/side-channel/-/side-channel-1.1.0.tgz", "license": "MIT",
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
"dependencies": { "dependencies": {
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
"object-inspect": "^1.13.3", "object-inspect": "^1.13.3",
@@ -814,8 +708,6 @@
}, },
"node_modules/side-channel-list": { "node_modules/side-channel-list": {
"version": "1.0.1", "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", "license": "MIT",
"dependencies": { "dependencies": {
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
@@ -830,8 +722,6 @@
}, },
"node_modules/side-channel-map": { "node_modules/side-channel-map": {
"version": "1.0.1", "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", "license": "MIT",
"dependencies": { "dependencies": {
"call-bound": "^1.0.2", "call-bound": "^1.0.2",
@@ -848,8 +738,6 @@
}, },
"node_modules/side-channel-weakmap": { "node_modules/side-channel-weakmap": {
"version": "1.0.2", "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", "license": "MIT",
"dependencies": { "dependencies": {
"call-bound": "^1.0.2", "call-bound": "^1.0.2",
@@ -867,8 +755,6 @@
}, },
"node_modules/statuses": { "node_modules/statuses": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://mirrors.tencent.com/npm/statuses/-/statuses-2.0.2.tgz",
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@@ -876,24 +762,19 @@
}, },
"node_modules/streamsearch": { "node_modules/streamsearch": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://mirrors.tencent.com/npm/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"
} }
}, },
"node_modules/string_decoder": { "node_modules/string_decoder": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://mirrors.tencent.com/npm/string_decoder/-/string_decoder-1.3.0.tgz", "license": "MIT",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"dependencies": { "dependencies": {
"safe-buffer": "~5.2.0" "safe-buffer": "~5.2.0"
} }
}, },
"node_modules/toidentifier": { "node_modules/toidentifier": {
"version": "1.0.1", "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", "license": "MIT",
"engines": { "engines": {
"node": ">=0.6" "node": ">=0.6"
@@ -901,8 +782,7 @@
}, },
"node_modules/type-is": { "node_modules/type-is": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://mirrors.tencent.com/npm/type-is/-/type-is-2.0.1.tgz", "license": "MIT",
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
"dependencies": { "dependencies": {
"content-type": "^1.0.5", "content-type": "^1.0.5",
"media-typer": "^1.1.0", "media-typer": "^1.1.0",
@@ -914,13 +794,10 @@
}, },
"node_modules/typedarray": { "node_modules/typedarray": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://mirrors.tencent.com/npm/typedarray/-/typedarray-0.0.6.tgz", "license": "MIT"
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
}, },
"node_modules/unpipe": { "node_modules/unpipe": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://mirrors.tencent.com/npm/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@@ -928,29 +805,23 @@
}, },
"node_modules/util-deprecate": { "node_modules/util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://mirrors.tencent.com/npm/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/vary": { "node_modules/vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://mirrors.tencent.com/npm/vary/-/vary-1.1.2.tgz", "license": "MIT",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/wrappy": { "node_modules/wrappy": {
"version": "1.0.2", "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" "license": "ISC"
}, },
"node_modules/ws": { "node_modules/ws": {
"version": "8.20.0", "version": "8.18.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", "resolved": "https://mirrors.tencent.com/npm/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"license": "MIT",
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"
}, },
+6 -15
View File
@@ -1,22 +1,13 @@
'use strict'; '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 WebSocket = require('./lib/websocket');
const WebSocketServer = require('./lib/websocket-server');
WebSocket.createWebSocketStream = createWebSocketStream; WebSocket.createWebSocketStream = require('./lib/stream');
WebSocket.extension = extension; WebSocket.Server = require('./lib/websocket-server');
WebSocket.PerMessageDeflate = PerMessageDeflate; WebSocket.Receiver = require('./lib/receiver');
WebSocket.Receiver = Receiver; WebSocket.Sender = require('./lib/sender');
WebSocket.Sender = Sender;
WebSocket.Server = WebSocketServer;
WebSocket.subprotocol = subprotocol;
WebSocket.WebSocket = WebSocket; WebSocket.WebSocket = WebSocket;
WebSocket.WebSocketServer = WebSocketServer; WebSocket.WebSocketServer = WebSocket.Server;
module.exports = WebSocket; module.exports = WebSocket;
-1
View File
@@ -7,7 +7,6 @@ if (hasBlob) BINARY_TYPES.push('blob');
module.exports = { module.exports = {
BINARY_TYPES, BINARY_TYPES,
CLOSE_TIMEOUT: 30000,
EMPTY_BUFFER: Buffer.alloc(0), EMPTY_BUFFER: Buffer.alloc(0),
GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
hasBlob, hasBlob,
+6 -20
View File
@@ -37,9 +37,6 @@ class PerMessageDeflate {
* acknowledge disabling of client context takeover * acknowledge disabling of client context takeover
* @param {Number} [options.concurrencyLimit=10] The number of concurrent * @param {Number} [options.concurrencyLimit=10] The number of concurrent
* calls to zlib * 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 * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the
* use of a custom server window size * use of a custom server window size
* @param {Boolean} [options.serverNoContextTakeover=false] Request/accept * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
@@ -50,13 +47,16 @@ class PerMessageDeflate {
* deflate * deflate
* @param {Object} [options.zlibInflateOptions] Options to pass to zlib on * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on
* inflate * 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._options = options || {};
this._threshold = this._threshold =
this._options.threshold !== undefined ? this._options.threshold : 1024; this._options.threshold !== undefined ? this._options.threshold : 1024;
this._maxPayload = this._options.maxPayload | 0; this._isServer = !!isServer;
this._isServer = !!this._options.isServer;
this._deflate = null; this._deflate = null;
this._inflate = null; this._inflate = null;
@@ -494,14 +494,6 @@ function inflateOnData(chunk) {
this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'; this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';
this[kError][kStatusCode] = 1009; this[kError][kStatusCode] = 1009;
this.removeListener('data', inflateOnData); 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(); this.reset();
} }
@@ -517,12 +509,6 @@ function inflateOnError(err) {
// closed when an error is emitted. // closed when an error is emitted.
// //
this[kPerMessageDeflate]._inflate = null; this[kPerMessageDeflate]._inflate = null;
if (this[kError]) {
this[kCallback](this[kError]);
return;
}
err[kStatusCode] = 1007; err[kStatusCode] = 1007;
this[kCallback](err); this[kCallback](err);
} }
+1 -1
View File
@@ -551,7 +551,7 @@ class Sender {
/** /**
* Sends a frame. * Sends a frame.
* *
* @param {(Buffer | String)[]} list The frame to send * @param {Buffer[]} list The frame to send
* @param {Function} [cb] Callback * @param {Function} [cb] Callback
* @private * @private
*/ */
-2
View File
@@ -1,7 +1,5 @@
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^WebSocket$" }] */
'use strict'; 'use strict';
const WebSocket = require('./websocket');
const { Duplex } = require('stream'); const { Duplex } = require('stream');
/** /**
+10 -24
View File
@@ -11,7 +11,7 @@ const extension = require('./extension');
const PerMessageDeflate = require('./permessage-deflate'); const PerMessageDeflate = require('./permessage-deflate');
const subprotocol = require('./subprotocol'); const subprotocol = require('./subprotocol');
const WebSocket = require('./websocket'); const WebSocket = require('./websocket');
const { CLOSE_TIMEOUT, GUID, kWebSocket } = require('./constants'); const { GUID, kWebSocket } = require('./constants');
const keyRegex = /^[+/0-9A-Za-z]{22}==$/; const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
@@ -38,9 +38,6 @@ class WebSocketServer extends EventEmitter {
* pending connections * pending connections
* @param {Boolean} [options.clientTracking=true] Specifies whether or not to * @param {Boolean} [options.clientTracking=true] Specifies whether or not to
* track clients * 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 {Function} [options.handleProtocols] A hook to handle protocols
* @param {String} [options.host] The hostname where to bind the server * @param {String} [options.host] The hostname where to bind the server
* @param {Number} [options.maxPayload=104857600] The maximum allowed message * @param {Number} [options.maxPayload=104857600] The maximum allowed message
@@ -70,7 +67,6 @@ class WebSocketServer extends EventEmitter {
perMessageDeflate: false, perMessageDeflate: false,
handleProtocols: null, handleProtocols: null,
clientTracking: true, clientTracking: true,
closeTimeout: CLOSE_TIMEOUT,
verifyClient: null, verifyClient: null,
noServer: false, noServer: false,
backlog: null, // use default (511 as implemented in net.js) backlog: null, // use default (511 as implemented in net.js)
@@ -260,11 +256,9 @@ class WebSocketServer extends EventEmitter {
return; return;
} }
if (version !== 13 && version !== 8) { if (version !== 8 && version !== 13) {
const message = 'Missing or invalid Sec-WebSocket-Version header'; const message = 'Missing or invalid Sec-WebSocket-Version header';
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message, { abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
'Sec-WebSocket-Version': '13, 8'
});
return; return;
} }
@@ -293,11 +287,11 @@ class WebSocketServer extends EventEmitter {
this.options.perMessageDeflate && this.options.perMessageDeflate &&
secWebSocketExtensions !== undefined secWebSocketExtensions !== undefined
) { ) {
const perMessageDeflate = new PerMessageDeflate({ const perMessageDeflate = new PerMessageDeflate(
...this.options.perMessageDeflate, this.options.perMessageDeflate,
isServer: true, true,
maxPayload: this.options.maxPayload this.options.maxPayload
}); );
try { try {
const offers = extension.parse(secWebSocketExtensions); 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 {Duplex} socket The socket of the upgrade request
* @param {Number} code The HTTP response status code * @param {Number} code The HTTP response status code
* @param {String} message The HTTP response body * @param {String} message The HTTP response body
* @param {Object} [headers] The HTTP response headers
* @private * @private
*/ */
function abortHandshakeOrEmitwsClientError( function abortHandshakeOrEmitwsClientError(server, req, socket, code, message) {
server,
req,
socket,
code,
message,
headers
) {
if (server.listenerCount('wsClientError')) { if (server.listenerCount('wsClientError')) {
const err = new Error(message); const err = new Error(message);
Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError); Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);
server.emit('wsClientError', err, socket, req); server.emit('wsClientError', err, socket, req);
} else { } else {
abortHandshake(socket, code, message, headers); abortHandshake(socket, code, message);
} }
} }
+15 -20
View File
@@ -18,7 +18,6 @@ const { isBlob } = require('./validation');
const { const {
BINARY_TYPES, BINARY_TYPES,
CLOSE_TIMEOUT,
EMPTY_BUFFER, EMPTY_BUFFER,
GUID, GUID,
kForOnEventAttribute, kForOnEventAttribute,
@@ -33,6 +32,7 @@ const {
const { format, parse } = require('./extension'); const { format, parse } = require('./extension');
const { toBuffer } = require('./buffer-util'); const { toBuffer } = require('./buffer-util');
const closeTimeout = 30 * 1000;
const kAborted = Symbol('kAborted'); const kAborted = Symbol('kAborted');
const protocolVersions = [8, 13]; const protocolVersions = [8, 13];
const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
@@ -88,7 +88,6 @@ class WebSocket extends EventEmitter {
initAsClient(this, address, protocols, options); initAsClient(this, address, protocols, options);
} else { } else {
this._autoPong = options.autoPong; this._autoPong = options.autoPong;
this._closeTimeout = options.closeTimeout;
this._isServer = true; this._isServer = true;
} }
} }
@@ -630,8 +629,6 @@ module.exports = WebSocket;
* times in the same tick * times in the same tick
* @param {Boolean} [options.autoPong=true] Specifies whether or not to * @param {Boolean} [options.autoPong=true] Specifies whether or not to
* automatically send a pong in response to a ping * 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 * @param {Function} [options.finishRequest] A function which can be used to
* customize the headers of each http request before it is sent * customize the headers of each http request before it is sent
* @param {Boolean} [options.followRedirects=false] Whether or not to follow * @param {Boolean} [options.followRedirects=false] Whether or not to follow
@@ -658,7 +655,6 @@ function initAsClient(websocket, address, protocols, options) {
const opts = { const opts = {
allowSynchronousEvents: true, allowSynchronousEvents: true,
autoPong: true, autoPong: true,
closeTimeout: CLOSE_TIMEOUT,
protocolVersion: protocolVersions[1], protocolVersion: protocolVersions[1],
maxPayload: 100 * 1024 * 1024, maxPayload: 100 * 1024 * 1024,
skipUTF8Validation: false, skipUTF8Validation: false,
@@ -677,7 +673,6 @@ function initAsClient(websocket, address, protocols, options) {
}; };
websocket._autoPong = opts.autoPong; websocket._autoPong = opts.autoPong;
websocket._closeTimeout = opts.closeTimeout;
if (!protocolVersions.includes(opts.protocolVersion)) { if (!protocolVersions.includes(opts.protocolVersion)) {
throw new RangeError( throw new RangeError(
@@ -693,7 +688,7 @@ function initAsClient(websocket, address, protocols, options) {
} else { } else {
try { try {
parsedUrl = new URL(address); parsedUrl = new URL(address);
} catch { } catch (e) {
throw new SyntaxError(`Invalid URL: ${address}`); throw new SyntaxError(`Invalid URL: ${address}`);
} }
} }
@@ -713,7 +708,7 @@ function initAsClient(websocket, address, protocols, options) {
if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) { if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {
invalidUrlMessage = invalidUrlMessage =
'The URL\'s protocol must be one of "ws:", "wss:", ' + '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) { } else if (isIpcUrl && !parsedUrl.pathname) {
invalidUrlMessage = "The URL's pathname is empty"; invalidUrlMessage = "The URL's pathname is empty";
} else if (parsedUrl.hash) { } else if (parsedUrl.hash) {
@@ -755,11 +750,11 @@ function initAsClient(websocket, address, protocols, options) {
opts.timeout = opts.handshakeTimeout; opts.timeout = opts.handshakeTimeout;
if (opts.perMessageDeflate) { if (opts.perMessageDeflate) {
perMessageDeflate = new PerMessageDeflate({ perMessageDeflate = new PerMessageDeflate(
...opts.perMessageDeflate, opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},
isServer: false, false,
maxPayload: opts.maxPayload opts.maxPayload
}); );
opts.headers['Sec-WebSocket-Extensions'] = format({ opts.headers['Sec-WebSocket-Extensions'] = format({
[PerMessageDeflate.extensionName]: perMessageDeflate.offer() [PerMessageDeflate.extensionName]: perMessageDeflate.offer()
}); });
@@ -1295,7 +1290,7 @@ function senderOnError(err) {
function setCloseTimer(websocket) { function setCloseTimer(websocket) {
websocket._closeTimer = setTimeout( websocket._closeTimer = setTimeout(
websocket._socket.destroy.bind(websocket._socket), websocket._socket.destroy.bind(websocket._socket),
websocket._closeTimeout closeTimeout
); );
} }
@@ -1313,23 +1308,23 @@ function socketOnClose() {
websocket._readyState = WebSocket.CLOSING; websocket._readyState = WebSocket.CLOSING;
let chunk;
// //
// The close frame might not have been received or the `'end'` event emitted, // 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 // 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 // `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 // 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 // buffered data as everything has been already written and `readable.read()`
// socket is paused, any possible buffered data will be read as a single // will return `null`. If instead, the socket is paused, any possible buffered
// chunk. // data will be read as a single chunk.
// //
if ( if (
!this._readableState.endEmitted && !this._readableState.endEmitted &&
!websocket._closeFrameReceived && !websocket._closeFrameReceived &&
!websocket._receiver._writableState.errorEmitted && !websocket._receiver._writableState.errorEmitted &&
this._readableState.length !== 0 (chunk = websocket._socket.read()) !== null
) { ) {
const chunk = this.read(this._readableState.length);
websocket._receiver.write(chunk); websocket._receiver.write(chunk);
} }
+4 -5
View File
@@ -1,6 +1,6 @@
{ {
"name": "ws", "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", "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
"keywords": [ "keywords": [
"HyBi", "HyBi",
@@ -55,13 +55,12 @@
} }
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^10.0.1",
"benchmark": "^2.1.4", "benchmark": "^2.1.4",
"bufferutil": "^4.0.1", "bufferutil": "^4.0.1",
"eslint": "^10.0.1", "eslint": "^9.0.0",
"eslint-config-prettier": "^10.0.1", "eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0", "eslint-plugin-prettier": "^5.0.0",
"globals": "^17.0.0", "globals": "^15.0.0",
"mocha": "^8.4.0", "mocha": "^8.4.0",
"nyc": "^15.0.0", "nyc": "^15.0.0",
"prettier": "^3.0.0", "prettier": "^3.0.0",
+1 -14
View File
@@ -1,21 +1,8 @@
import createWebSocketStream from './lib/stream.js'; 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 Receiver from './lib/receiver.js';
import Sender from './lib/sender.js'; import Sender from './lib/sender.js';
import subprotocol from './lib/subprotocol.js';
import WebSocket from './lib/websocket.js'; import WebSocket from './lib/websocket.js';
import WebSocketServer from './lib/websocket-server.js'; import WebSocketServer from './lib/websocket-server.js';
export { export { createWebSocketStream, Receiver, Sender, WebSocket, WebSocketServer };
createWebSocketStream,
extension,
PerMessageDeflate,
Receiver,
Sender,
subprotocol,
WebSocket,
WebSocketServer
};
export default WebSocket; export default WebSocket;
+37 -166
View File
@@ -10,13 +10,11 @@
"dependencies": { "dependencies": {
"express": "^5.2.1", "express": "^5.2.1",
"multer": "^2.1.1", "multer": "^2.1.1",
"ws": "^8.16.0" "ws": "8.18.0"
} }
}, },
"node_modules/accepts": { "node_modules/accepts": {
"version": "2.0.0", "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", "license": "MIT",
"dependencies": { "dependencies": {
"mime-types": "^3.0.0", "mime-types": "^3.0.0",
@@ -28,14 +26,10 @@
}, },
"node_modules/append-field": { "node_modules/append-field": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://mirrors.tencent.com/npm/append-field/-/append-field-1.0.0.tgz",
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/body-parser": { "node_modules/body-parser": {
"version": "2.2.2", "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", "license": "MIT",
"dependencies": { "dependencies": {
"bytes": "^3.1.2", "bytes": "^3.1.2",
@@ -58,14 +52,10 @@
}, },
"node_modules/buffer-from": { "node_modules/buffer-from": {
"version": "1.1.2", "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" "license": "MIT"
}, },
"node_modules/busboy": { "node_modules/busboy": {
"version": "1.6.0", "version": "1.6.0",
"resolved": "https://mirrors.tencent.com/npm/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"dependencies": { "dependencies": {
"streamsearch": "^1.1.0" "streamsearch": "^1.1.0"
}, },
@@ -75,8 +65,6 @@
}, },
"node_modules/bytes": { "node_modules/bytes": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://mirrors.tencent.com/npm/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@@ -84,8 +72,7 @@
}, },
"node_modules/call-bind-apply-helpers": { "node_modules/call-bind-apply-helpers": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://mirrors.tencent.com/npm/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "license": "MIT",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dependencies": { "dependencies": {
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
"function-bind": "^1.1.2" "function-bind": "^1.1.2"
@@ -96,8 +83,6 @@
}, },
"node_modules/call-bound": { "node_modules/call-bound": {
"version": "1.0.4", "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", "license": "MIT",
"dependencies": { "dependencies": {
"call-bind-apply-helpers": "^1.0.2", "call-bind-apply-helpers": "^1.0.2",
@@ -112,11 +97,10 @@
}, },
"node_modules/concat-stream": { "node_modules/concat-stream": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://mirrors.tencent.com/npm/concat-stream/-/concat-stream-2.0.0.tgz",
"integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
"engines": [ "engines": [
"node >= 6.0" "node >= 6.0"
], ],
"license": "MIT",
"dependencies": { "dependencies": {
"buffer-from": "^1.0.0", "buffer-from": "^1.0.0",
"inherits": "^2.0.3", "inherits": "^2.0.3",
@@ -126,8 +110,6 @@
}, },
"node_modules/content-disposition": { "node_modules/content-disposition": {
"version": "1.1.0", "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", "license": "MIT",
"engines": { "engines": {
"node": ">=18" "node": ">=18"
@@ -139,16 +121,13 @@
}, },
"node_modules/content-type": { "node_modules/content-type": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://mirrors.tencent.com/npm/content-type/-/content-type-1.0.5.tgz", "license": "MIT",
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/cookie": { "node_modules/cookie": {
"version": "0.7.2", "version": "0.7.2",
"resolved": "https://mirrors.tencent.com/npm/cookie/-/cookie-0.7.2.tgz",
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -156,8 +135,6 @@
}, },
"node_modules/cookie-signature": { "node_modules/cookie-signature": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://mirrors.tencent.com/npm/cookie-signature/-/cookie-signature-1.2.2.tgz",
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.6.0" "node": ">=6.6.0"
@@ -165,8 +142,6 @@
}, },
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.3", "version": "4.4.3",
"resolved": "https://mirrors.tencent.com/npm/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ms": "^2.1.3" "ms": "^2.1.3"
@@ -182,8 +157,6 @@
}, },
"node_modules/depd": { "node_modules/depd": {
"version": "2.0.0", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@@ -191,8 +164,6 @@
}, },
"node_modules/dunder-proto": { "node_modules/dunder-proto": {
"version": "1.0.1", "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", "license": "MIT",
"dependencies": { "dependencies": {
"call-bind-apply-helpers": "^1.0.1", "call-bind-apply-helpers": "^1.0.1",
@@ -205,13 +176,10 @@
}, },
"node_modules/ee-first": { "node_modules/ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://mirrors.tencent.com/npm/ee-first/-/ee-first-1.1.1.tgz", "license": "MIT"
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
}, },
"node_modules/encodeurl": { "node_modules/encodeurl": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://mirrors.tencent.com/npm/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@@ -219,8 +187,6 @@
}, },
"node_modules/es-define-property": { "node_modules/es-define-property": {
"version": "1.0.1", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@@ -228,16 +194,14 @@
}, },
"node_modules/es-errors": { "node_modules/es-errors": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://mirrors.tencent.com/npm/es-errors/-/es-errors-1.3.0.tgz", "license": "MIT",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/es-object-atoms": { "node_modules/es-object-atoms": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://mirrors.tencent.com/npm/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "license": "MIT",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"dependencies": { "dependencies": {
"es-errors": "^1.3.0" "es-errors": "^1.3.0"
}, },
@@ -247,13 +211,10 @@
}, },
"node_modules/escape-html": { "node_modules/escape-html": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://mirrors.tencent.com/npm/escape-html/-/escape-html-1.0.3.tgz", "license": "MIT"
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
}, },
"node_modules/etag": { "node_modules/etag": {
"version": "1.8.1", "version": "1.8.1",
"resolved": "https://mirrors.tencent.com/npm/etag/-/etag-1.8.1.tgz",
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -261,8 +222,6 @@
}, },
"node_modules/express": { "node_modules/express": {
"version": "5.2.1", "version": "5.2.1",
"resolved": "https://mirrors.tencent.com/npm/express/-/express-5.2.1.tgz",
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"accepts": "^2.0.0", "accepts": "^2.0.0",
@@ -304,8 +263,6 @@
}, },
"node_modules/finalhandler": { "node_modules/finalhandler": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://mirrors.tencent.com/npm/finalhandler/-/finalhandler-2.1.1.tgz",
"integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"debug": "^4.4.0", "debug": "^4.4.0",
@@ -325,8 +282,6 @@
}, },
"node_modules/forwarded": { "node_modules/forwarded": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://mirrors.tencent.com/npm/forwarded/-/forwarded-0.2.0.tgz",
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -334,16 +289,13 @@
}, },
"node_modules/fresh": { "node_modules/fresh": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://mirrors.tencent.com/npm/fresh/-/fresh-2.0.0.tgz", "license": "MIT",
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/function-bind": { "node_modules/function-bind": {
"version": "1.1.2", "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", "license": "MIT",
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
@@ -351,8 +303,7 @@
}, },
"node_modules/get-intrinsic": { "node_modules/get-intrinsic": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://mirrors.tencent.com/npm/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "license": "MIT",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dependencies": { "dependencies": {
"call-bind-apply-helpers": "^1.0.2", "call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1", "es-define-property": "^1.0.1",
@@ -374,8 +325,6 @@
}, },
"node_modules/get-proto": { "node_modules/get-proto": {
"version": "1.0.1", "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", "license": "MIT",
"dependencies": { "dependencies": {
"dunder-proto": "^1.0.1", "dunder-proto": "^1.0.1",
@@ -387,8 +336,7 @@
}, },
"node_modules/gopd": { "node_modules/gopd": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://mirrors.tencent.com/npm/gopd/-/gopd-1.2.0.tgz", "license": "MIT",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
}, },
@@ -398,8 +346,7 @@
}, },
"node_modules/has-symbols": { "node_modules/has-symbols": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://mirrors.tencent.com/npm/has-symbols/-/has-symbols-1.1.0.tgz", "license": "MIT",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
}, },
@@ -409,8 +356,7 @@
}, },
"node_modules/hasown": { "node_modules/hasown": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://mirrors.tencent.com/npm/hasown/-/hasown-2.0.3.tgz", "license": "MIT",
"integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
"dependencies": { "dependencies": {
"function-bind": "^1.1.2" "function-bind": "^1.1.2"
}, },
@@ -420,8 +366,7 @@
}, },
"node_modules/http-errors": { "node_modules/http-errors": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://mirrors.tencent.com/npm/http-errors/-/http-errors-2.0.1.tgz", "license": "MIT",
"integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
"dependencies": { "dependencies": {
"depd": "~2.0.0", "depd": "~2.0.0",
"inherits": "~2.0.4", "inherits": "~2.0.4",
@@ -439,8 +384,6 @@
}, },
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.7.2", "version": "0.7.2",
"resolved": "https://mirrors.tencent.com/npm/iconv-lite/-/iconv-lite-0.7.2.tgz",
"integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0" "safer-buffer": ">= 2.1.2 < 3.0.0"
@@ -455,14 +398,10 @@
}, },
"node_modules/inherits": { "node_modules/inherits": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://mirrors.tencent.com/npm/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/ipaddr.js": { "node_modules/ipaddr.js": {
"version": "1.9.1", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.10" "node": ">= 0.10"
@@ -470,14 +409,10 @@
}, },
"node_modules/is-promise": { "node_modules/is-promise": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://mirrors.tencent.com/npm/is-promise/-/is-promise-4.0.0.tgz",
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/math-intrinsics": { "node_modules/math-intrinsics": {
"version": "1.1.0", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@@ -485,8 +420,6 @@
}, },
"node_modules/media-typer": { "node_modules/media-typer": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://mirrors.tencent.com/npm/media-typer/-/media-typer-1.1.0.tgz",
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@@ -494,8 +427,6 @@
}, },
"node_modules/merge-descriptors": { "node_modules/merge-descriptors": {
"version": "2.0.0", "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", "license": "MIT",
"engines": { "engines": {
"node": ">=18" "node": ">=18"
@@ -506,8 +437,6 @@
}, },
"node_modules/mime-db": { "node_modules/mime-db": {
"version": "1.54.0", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -515,8 +444,7 @@
}, },
"node_modules/mime-types": { "node_modules/mime-types": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://mirrors.tencent.com/npm/mime-types/-/mime-types-3.0.2.tgz", "license": "MIT",
"integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
"dependencies": { "dependencies": {
"mime-db": "^1.54.0" "mime-db": "^1.54.0"
}, },
@@ -530,13 +458,10 @@
}, },
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://mirrors.tencent.com/npm/ms/-/ms-2.1.3.tgz", "license": "MIT"
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
}, },
"node_modules/multer": { "node_modules/multer": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://mirrors.tencent.com/npm/multer/-/multer-2.1.1.tgz",
"integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"append-field": "^1.0.0", "append-field": "^1.0.0",
@@ -554,8 +479,6 @@
}, },
"node_modules/multer/node_modules/media-typer": { "node_modules/multer/node_modules/media-typer": {
"version": "0.3.0", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -563,8 +486,6 @@
}, },
"node_modules/multer/node_modules/mime-db": { "node_modules/multer/node_modules/mime-db": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://mirrors.tencent.com/npm/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -572,8 +493,7 @@
}, },
"node_modules/multer/node_modules/mime-types": { "node_modules/multer/node_modules/mime-types": {
"version": "2.1.35", "version": "2.1.35",
"resolved": "https://mirrors.tencent.com/npm/mime-types/-/mime-types-2.1.35.tgz", "license": "MIT",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": { "dependencies": {
"mime-db": "1.52.0" "mime-db": "1.52.0"
}, },
@@ -583,8 +503,7 @@
}, },
"node_modules/multer/node_modules/type-is": { "node_modules/multer/node_modules/type-is": {
"version": "1.6.18", "version": "1.6.18",
"resolved": "https://mirrors.tencent.com/npm/type-is/-/type-is-1.6.18.tgz", "license": "MIT",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"dependencies": { "dependencies": {
"media-typer": "0.3.0", "media-typer": "0.3.0",
"mime-types": "~2.1.24" "mime-types": "~2.1.24"
@@ -595,8 +514,6 @@
}, },
"node_modules/negotiator": { "node_modules/negotiator": {
"version": "1.0.0", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -604,8 +521,6 @@
}, },
"node_modules/object-inspect": { "node_modules/object-inspect": {
"version": "1.13.4", "version": "1.13.4",
"resolved": "https://mirrors.tencent.com/npm/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@@ -616,8 +531,7 @@
}, },
"node_modules/on-finished": { "node_modules/on-finished": {
"version": "2.4.1", "version": "2.4.1",
"resolved": "https://mirrors.tencent.com/npm/on-finished/-/on-finished-2.4.1.tgz", "license": "MIT",
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"dependencies": { "dependencies": {
"ee-first": "1.1.1" "ee-first": "1.1.1"
}, },
@@ -627,24 +541,21 @@
}, },
"node_modules/once": { "node_modules/once": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://mirrors.tencent.com/npm/once/-/once-1.4.0.tgz", "license": "ISC",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dependencies": { "dependencies": {
"wrappy": "1" "wrappy": "1"
} }
}, },
"node_modules/parseurl": { "node_modules/parseurl": {
"version": "1.3.3", "version": "1.3.3",
"resolved": "https://mirrors.tencent.com/npm/parseurl/-/parseurl-1.3.3.tgz", "license": "MIT",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/path-to-regexp": { "node_modules/path-to-regexp": {
"version": "8.4.2", "version": "8.4.2",
"resolved": "https://mirrors.tencent.com/npm/path-to-regexp/-/path-to-regexp-8.4.2.tgz", "license": "MIT",
"integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==",
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/express" "url": "https://opencollective.com/express"
@@ -652,8 +563,6 @@
}, },
"node_modules/proxy-addr": { "node_modules/proxy-addr": {
"version": "2.0.7", "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", "license": "MIT",
"dependencies": { "dependencies": {
"forwarded": "0.2.0", "forwarded": "0.2.0",
@@ -665,8 +574,6 @@
}, },
"node_modules/qs": { "node_modules/qs": {
"version": "6.15.1", "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", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"side-channel": "^1.1.0" "side-channel": "^1.1.0"
@@ -680,8 +587,6 @@
}, },
"node_modules/range-parser": { "node_modules/range-parser": {
"version": "1.2.1", "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", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -689,8 +594,7 @@
}, },
"node_modules/raw-body": { "node_modules/raw-body": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://mirrors.tencent.com/npm/raw-body/-/raw-body-3.0.2.tgz", "license": "MIT",
"integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
"dependencies": { "dependencies": {
"bytes": "~3.1.2", "bytes": "~3.1.2",
"http-errors": "~2.0.1", "http-errors": "~2.0.1",
@@ -703,8 +607,7 @@
}, },
"node_modules/readable-stream": { "node_modules/readable-stream": {
"version": "3.6.2", "version": "3.6.2",
"resolved": "https://mirrors.tencent.com/npm/readable-stream/-/readable-stream-3.6.2.tgz", "license": "MIT",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dependencies": { "dependencies": {
"inherits": "^2.0.3", "inherits": "^2.0.3",
"string_decoder": "^1.1.1", "string_decoder": "^1.1.1",
@@ -716,8 +619,6 @@
}, },
"node_modules/router": { "node_modules/router": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://mirrors.tencent.com/npm/router/-/router-2.2.0.tgz",
"integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"debug": "^4.4.0", "debug": "^4.4.0",
@@ -732,8 +633,6 @@
}, },
"node_modules/safe-buffer": { "node_modules/safe-buffer": {
"version": "5.2.1", "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": [ "funding": [
{ {
"type": "github", "type": "github",
@@ -747,17 +646,16 @@
"type": "consulting", "type": "consulting",
"url": "https://feross.org/support" "url": "https://feross.org/support"
} }
] ],
"license": "MIT"
}, },
"node_modules/safer-buffer": { "node_modules/safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://mirrors.tencent.com/npm/safer-buffer/-/safer-buffer-2.1.2.tgz", "license": "MIT"
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"node_modules/send": { "node_modules/send": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://mirrors.tencent.com/npm/send/-/send-1.2.1.tgz", "license": "MIT",
"integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
"dependencies": { "dependencies": {
"debug": "^4.4.3", "debug": "^4.4.3",
"encodeurl": "^2.0.0", "encodeurl": "^2.0.0",
@@ -781,8 +679,6 @@
}, },
"node_modules/serve-static": { "node_modules/serve-static": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://mirrors.tencent.com/npm/serve-static/-/serve-static-2.2.1.tgz",
"integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"encodeurl": "^2.0.0", "encodeurl": "^2.0.0",
@@ -800,13 +696,11 @@
}, },
"node_modules/setprototypeof": { "node_modules/setprototypeof": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://mirrors.tencent.com/npm/setprototypeof/-/setprototypeof-1.2.0.tgz", "license": "ISC"
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
}, },
"node_modules/side-channel": { "node_modules/side-channel": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://mirrors.tencent.com/npm/side-channel/-/side-channel-1.1.0.tgz", "license": "MIT",
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
"dependencies": { "dependencies": {
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
"object-inspect": "^1.13.3", "object-inspect": "^1.13.3",
@@ -823,8 +717,6 @@
}, },
"node_modules/side-channel-list": { "node_modules/side-channel-list": {
"version": "1.0.1", "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", "license": "MIT",
"dependencies": { "dependencies": {
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
@@ -839,8 +731,6 @@
}, },
"node_modules/side-channel-map": { "node_modules/side-channel-map": {
"version": "1.0.1", "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", "license": "MIT",
"dependencies": { "dependencies": {
"call-bound": "^1.0.2", "call-bound": "^1.0.2",
@@ -857,8 +747,6 @@
}, },
"node_modules/side-channel-weakmap": { "node_modules/side-channel-weakmap": {
"version": "1.0.2", "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", "license": "MIT",
"dependencies": { "dependencies": {
"call-bound": "^1.0.2", "call-bound": "^1.0.2",
@@ -876,8 +764,6 @@
}, },
"node_modules/statuses": { "node_modules/statuses": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://mirrors.tencent.com/npm/statuses/-/statuses-2.0.2.tgz",
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@@ -885,24 +771,19 @@
}, },
"node_modules/streamsearch": { "node_modules/streamsearch": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://mirrors.tencent.com/npm/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"
} }
}, },
"node_modules/string_decoder": { "node_modules/string_decoder": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://mirrors.tencent.com/npm/string_decoder/-/string_decoder-1.3.0.tgz", "license": "MIT",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"dependencies": { "dependencies": {
"safe-buffer": "~5.2.0" "safe-buffer": "~5.2.0"
} }
}, },
"node_modules/toidentifier": { "node_modules/toidentifier": {
"version": "1.0.1", "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", "license": "MIT",
"engines": { "engines": {
"node": ">=0.6" "node": ">=0.6"
@@ -910,8 +791,7 @@
}, },
"node_modules/type-is": { "node_modules/type-is": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://mirrors.tencent.com/npm/type-is/-/type-is-2.0.1.tgz", "license": "MIT",
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
"dependencies": { "dependencies": {
"content-type": "^1.0.5", "content-type": "^1.0.5",
"media-typer": "^1.1.0", "media-typer": "^1.1.0",
@@ -923,13 +803,10 @@
}, },
"node_modules/typedarray": { "node_modules/typedarray": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://mirrors.tencent.com/npm/typedarray/-/typedarray-0.0.6.tgz", "license": "MIT"
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
}, },
"node_modules/unpipe": { "node_modules/unpipe": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://mirrors.tencent.com/npm/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@@ -937,29 +814,23 @@
}, },
"node_modules/util-deprecate": { "node_modules/util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://mirrors.tencent.com/npm/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/vary": { "node_modules/vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://mirrors.tencent.com/npm/vary/-/vary-1.1.2.tgz", "license": "MIT",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/wrappy": { "node_modules/wrappy": {
"version": "1.0.2", "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" "license": "ISC"
}, },
"node_modules/ws": { "node_modules/ws": {
"version": "8.20.0", "version": "8.18.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", "resolved": "https://mirrors.tencent.com/npm/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"license": "MIT",
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"
}, },
+1 -1
View File
@@ -11,6 +11,6 @@
"dependencies": { "dependencies": {
"express": "^5.2.1", "express": "^5.2.1",
"multer": "^2.1.1", "multer": "^2.1.1",
"ws": "^8.16.0" "ws": "8.18.0"
} }
} }
+2 -2
View File
@@ -13,7 +13,7 @@ exec > >(tee -a "$LOG") 2>&1
SERVER_DIR="/Users/hanchengxi/workspace/tankwar_proj/server" SERVER_DIR="/Users/hanchengxi/workspace/tankwar_proj/server"
MASTER="root@host_172.16.16.16" 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" REMOTE_BUILD_DIR="/tmp/tankwar-build"
IMAGE_NAME="tankwar/tankwar-server:latest" 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 =====" echo "$(ts) ===== Syncing tankwar server source to master node ====="
ssh -o StrictHostKeyChecking=no "$MASTER" "mkdir -p $REMOTE_BUILD_DIR" 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" \ -e "ssh -o StrictHostKeyChecking=no" \
"$SERVER_DIR/" "${MASTER}:${REMOTE_BUILD_DIR}/server/" "$SERVER_DIR/" "${MASTER}:${REMOTE_BUILD_DIR}/server/"
echo "$(ts) ✓ Source synced" echo "$(ts) ✓ Source synced"