update:新版本websocket

This commit is contained in:
2026-07-10 13:57:09 +08:00
parent 58a7bb2017
commit b5373bee31
11 changed files with 216 additions and 31 deletions
+93 -8
View File
@@ -30,6 +30,7 @@ const pendingAcks = [];
const ACK_AUDIO_TIMEOUT_MS = 9000;
const READY_ROUTE_FALLBACK_DELAY_MS = 300;
const ROUND_AUDIO_NAMES = ["一", "二", "三", "四", "五"];
const MATCH_STATUS_HALF_REST = 3;
// 比赛服消息类型先映射成项目里已有的 V2 业务消息,页面仍然复用原来的 socket-inbox 流程。
const BUSINESS_TYPE_BY_SERVER_TYPE = {
@@ -39,7 +40,6 @@ const BUSINESS_TYPE_BY_SERVER_TYPE = {
[ServerMessageType.SERVER_MSG_SHOT]: MESSAGETYPESV2.ShootResult,
[ServerMessageType.SERVER_MSG_NEW_ROUND]: MESSAGETYPESV2.NewRound,
[ServerMessageType.SERVER_MSG_MATCH_END]: MESSAGETYPESV2.BattleEnd,
[ServerMessageType.SERVER_MSG_TIMEOUT]: MESSAGETYPESV2.BattleEnd,
[ServerMessageType.SERVER_MSG_CHECK]: MESSAGETYPESV2.TestDistance,
[ServerMessageType.SERVER_MSG_NOT_ENOUGH_DISTANCE]: MESSAGETYPESV2.InvalidShot,
[ServerMessageType.SERVER_MSG_PRACTICE_END]: MESSAGETYPESV2.BattleEnd,
@@ -76,12 +76,73 @@ function normalizePracticeInfo(practiceInfo = {}) {
return normalized;
}
function getCurrentMode(message = {}, normalizedInfo = {}) {
const mode = Number(
pickField(message, "mode") ??
normalizedInfo.mode ??
currentContext?.mode
);
return Number.isFinite(mode) ? mode : undefined;
}
function isMeleeMessage(message = {}, normalizedInfo = {}) {
const mode = getCurrentMode(message, normalizedInfo);
if (mode !== undefined) return mode > 3;
if (currentContext?.isMelee !== undefined) return currentContext.isMelee;
return normalizeRoute(getCurrentPageInfo()?.route) === "pages/melee-battle";
}
function isHalfRestTimeout(message = {}, matchInfo = {}) {
if (message.type !== ServerMessageType.SERVER_MSG_TIMEOUT) return false;
if (!isMeleeMessage(message, matchInfo)) return false;
const status = Number(pickField(message, "status") ?? matchInfo.status);
return status === MATCH_STATUS_HALF_REST || !Number.isFinite(status);
}
function getBusinessType(message, matchInfo) {
if (isHalfRestTimeout(message, matchInfo)) return MESSAGETYPESV2.HalfRest;
if (message.type === ServerMessageType.SERVER_MSG_TIMEOUT) {
return MESSAGETYPESV2.BattleEnd;
}
return BUSINESS_TYPE_BY_SERVER_TYPE[message.type];
}
function buildBusinessMessage(message) {
const businessType = BUSINESS_TYPE_BY_SERVER_TYPE[message.type];
const matchInfo = normalizeMatchInfo(message.match_info);
if (
message.type === ServerMessageType.SERVER_MSG_MATCH_READY &&
(matchInfo.status === undefined ||
matchInfo.status === null ||
matchInfo.status === "")
) {
matchInfo.status = 0;
}
const practiceInfo = normalizePracticeInfo(message.practice_info);
const businessType = getBusinessType(message, matchInfo);
if (!businessType) return null;
const matchInfo = normalizeMatchInfo(message.match_info);
const practiceInfo = normalizePracticeInfo(message.practice_info);
const mode = getCurrentMode(message, matchInfo);
const isMelee = isMeleeMessage(message, matchInfo);
const isSecondHalfStart =
message.type === ServerMessageType.SERVER_MSG_MATCH_START &&
isMelee &&
currentContext?.meleeHalfRest === true;
if (currentContext) {
if (mode !== undefined) {
currentContext.mode = mode;
currentContext.isMelee = isMelee;
} else if (isMelee) {
currentContext.isMelee = true;
}
if (businessType === MESSAGETYPESV2.HalfRest) {
currentContext.meleeHalfRest = true;
} else if (message.type === ServerMessageType.SERVER_MSG_MATCH_START) {
currentContext.meleeHalfRest = false;
}
}
const matchId = normalizeId(
pickField(message, "matchId", "match_id") ||
matchInfo.matchId ||
@@ -109,6 +170,7 @@ function buildBusinessMessage(message) {
timestamp: message.timestamp,
matchWsType: message.type,
matchWsTypeName: getServerMessageTypeName(message.type),
isSecondHalfStart,
};
}
@@ -250,13 +312,23 @@ function getTestDistanceAudioKeys(shootData) {
function getAckAudioKeys(message, businessMessage) {
switch (message.type) {
case ServerMessageType.SERVER_MSG_MATCH_START:
return ["比赛开始"];
return [businessMessage?.isSecondHalfStart ? "下半场开始" : "比赛开始"];
case ServerMessageType.SERVER_MSG_NOW_YOU:
if (isMeleeMessage(message, businessMessage)) return [];
return getNowYouAudioKeys(businessMessage);
case ServerMessageType.SERVER_MSG_SHOT:
if (
isMeleeMessage(message, businessMessage) &&
String(businessMessage?.shootData?.playerId) !== String(currentContext?.userId)
) {
return [];
}
return getShootResultAudioKeys(businessMessage?.shootData);
case ServerMessageType.SERVER_MSG_MATCH_END:
return ["比赛结束"];
case ServerMessageType.SERVER_MSG_TIMEOUT:
if (businessMessage?.type === MESSAGETYPESV2.HalfRest) return ["中场休息"];
return ["比赛结束"];
case ServerMessageType.SERVER_MSG_PRACTICE_END:
return ["比赛结束"];
case ServerMessageType.SERVER_MSG_CHECK:
@@ -268,7 +340,14 @@ function getAckAudioKeys(message, businessMessage) {
}
}
function shouldCloseAfterAck(message) {
function shouldCloseAfterAck(message, businessMessage) {
if (
message.type === ServerMessageType.SERVER_MSG_TIMEOUT &&
businessMessage?.type === MESSAGETYPESV2.HalfRest
) {
return false;
}
return (
message.type === ServerMessageType.SERVER_MSG_MATCH_END ||
message.type === ServerMessageType.SERVER_MSG_TIMEOUT ||
@@ -416,7 +495,7 @@ function queueAckAfterAudio(message, businessMessage) {
pickField(message, "matchId", "match_id") || currentContext?.matchId
),
sequence: message.sequence,
leaveAfterAck: shouldCloseAfterAck(message),
leaveAfterAck: shouldCloseAfterAck(message, businessMessage),
};
const audioKeys = getAckAudioKeys(message, businessMessage).filter(Boolean);
@@ -503,10 +582,11 @@ function sendLeave() {
export function connectMatchWebSocket(options = {}) {
// 入口参数来自原 websocket 的比赛服地址通知,不影响原有 websocket 连接。
const { serverAddr, matchId, userId, token } = options;
const { serverAddr, matchId, userId, token, mode } = options;
const url = normalizeServerUrl(serverAddr, token);
const normalizedMatchId = normalizeId(matchId);
const normalizedUserId = normalizeId(userId);
const normalizedMode = Number(mode);
if (!url || !normalizedMatchId) {
console.log("[match-ws] missing serverAddr or matchId", options);
@@ -536,6 +616,10 @@ export function connectMatchWebSocket(options = {}) {
matchId: normalizedMatchId,
userId: normalizedUserId,
url,
mode: Number.isFinite(normalizedMode) ? normalizedMode : undefined,
isMelee:
Number.isFinite(normalizedMode) ? normalizedMode > 3 : undefined,
meleeHalfRest: false,
};
ensureAudioAckListener();
@@ -596,6 +680,7 @@ export function connectMatchWebSocketFromNotice(notice, fallbackUserId) {
serverAddr: pickField(notice, "serverAddr", "server_addr"),
matchId: pickField(notice, "matchId", "match_id"),
userId: pickField(notice, "userId", "user_id") || fallbackUserId,
mode: pickField(notice, "mode"),
token: notice.token || notice.wsToken || notice.ws_token,
});
}