тест 9
This commit is contained in:
@@ -308,6 +308,82 @@
|
||||
return String(window.HockeyAgentRuntime?.currentDeviceId?.() || localStorage.getItem(storage.vmixDevice) || "").trim();
|
||||
}
|
||||
|
||||
function rememberAssignedAgent(deviceId) {
|
||||
const clean = String(deviceId || "").trim();
|
||||
if (!clean) return;
|
||||
localStorage.setItem(storage.vmixDevice, clean);
|
||||
try { window.HockeyAgentRuntime?.selectDevice?.(clean); } catch (_) {}
|
||||
}
|
||||
|
||||
async function ensureSessionAgentAssignment(session) {
|
||||
const token = String(session?.token || localStorage.getItem(storage.session) || "").trim();
|
||||
let assignment = session?.agent_assignment && typeof session.agent_assignment === "object"
|
||||
? session.agent_assignment
|
||||
: null;
|
||||
|
||||
if (assignment?.device_id) rememberAssignedAgent(assignment.device_id);
|
||||
if (assignment?.delivered) return assignment;
|
||||
if (!token) return assignment;
|
||||
|
||||
// BUILD111: opening the web match is not proof that Agent received
|
||||
// match.assign. Recover from stale/empty localStorage only when routing is
|
||||
// unambiguous: the selected live Agent or exactly one live active Agent.
|
||||
let devicesPayload = null;
|
||||
try {
|
||||
devicesPayload = await request("/api/hockey/agents/devices", { timeoutMs: 3500 });
|
||||
} catch (_) {
|
||||
return assignment;
|
||||
}
|
||||
const devices = Array.isArray(devicesPayload?.devices) ? devicesPayload.devices : [];
|
||||
const live = devices.filter((item) => (
|
||||
item?.paired_to_me
|
||||
&& item?.active_for_account
|
||||
&& item?.online
|
||||
));
|
||||
const preferredIds = [
|
||||
String(assignment?.device_id || "").trim(),
|
||||
currentAgentDeviceId(),
|
||||
].filter(Boolean);
|
||||
let target = null;
|
||||
for (const preferred of preferredIds) {
|
||||
target = live.find((item) => String(item.device_id || "") === preferred) || null;
|
||||
if (target) break;
|
||||
}
|
||||
if (!target && live.length === 1) target = live[0];
|
||||
if (!target?.device_id) return assignment;
|
||||
|
||||
try {
|
||||
const rebound = await request(
|
||||
`/api/hockey/agents/devices/${encodeURIComponent(target.device_id)}/select-session`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ session_token: token, apply_mapping: false }),
|
||||
timeoutMs: 5000,
|
||||
}
|
||||
);
|
||||
assignment = rebound?.assignment || assignment;
|
||||
if (assignment?.device_id) rememberAssignedAgent(assignment.device_id);
|
||||
if (session && assignment) session.agent_assignment = assignment;
|
||||
return assignment;
|
||||
} catch (error) {
|
||||
console.warn("[Hockey] Agent match.assign retry failed:", error);
|
||||
return assignment;
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshSessionAgentMapping(session) {
|
||||
const assignment = await ensureSessionAgentAssignment(session);
|
||||
const deviceId = String(assignment?.device_id || "").trim();
|
||||
if (!deviceId || !assignment?.delivered) {
|
||||
return { ok: false, reason: "agent_match_not_delivered" };
|
||||
}
|
||||
return request(
|
||||
`/api/hockey/agents/devices/${encodeURIComponent(deviceId)}/apply-mapping`,
|
||||
{ method: "POST", timeoutMs: 60000 }
|
||||
);
|
||||
}
|
||||
|
||||
async function ensureAccountScopedRuntimeState() {
|
||||
let user = null;
|
||||
try {
|
||||
@@ -1660,6 +1736,12 @@ function gameCard(game) {
|
||||
}
|
||||
}
|
||||
|
||||
// Confirm that the concrete Agent actually received this new match.
|
||||
// A successful /sessions response alone is not enough: assignment may be
|
||||
// null/offline when the browser stored a stale device id.
|
||||
const initialAgentAssignment = await ensureSessionAgentAssignment(session);
|
||||
if (initialAgentAssignment && session) session.agent_assignment = initialAgentAssignment;
|
||||
|
||||
state.lastGameOpenError = "";
|
||||
state.selectedGameId = String(id);
|
||||
localStorage.setItem(storage.game, state.selectedGameId);
|
||||
@@ -1700,17 +1782,34 @@ function gameCard(game) {
|
||||
if (
|
||||
generation === state.gameOpenGeneration
|
||||
&& String(state.selectedGameId || "") === String(id)
|
||||
) startSelectedGamePolling();
|
||||
) {
|
||||
startSelectedGamePolling();
|
||||
void refreshSessionAgentMapping(session).then((mapping) => {
|
||||
if (mapping?.ok === false && mapping?.reason === "agent_match_not_delivered") {
|
||||
notify("Матч открыт, но Agent не получил новый матч", true);
|
||||
}
|
||||
}).catch((error) => console.warn("[Hockey] Mapping refresh after roster failed:", error));
|
||||
}
|
||||
} else if (!manual) {
|
||||
// This exact match already has its own cached roster, so vMix can be
|
||||
// refreshed immediately without waiting for the optional network sync.
|
||||
void refreshSessionAgentMapping(session).then((mapping) => {
|
||||
if (mapping?.ok === false && mapping?.reason === "agent_match_not_delivered") {
|
||||
notify("Матч открыт, но Agent не получил новый матч", true);
|
||||
}
|
||||
}).catch((error) => console.warn("[Hockey] Mapping refresh from cached roster failed:", error));
|
||||
void enrichOpenedGame(String(id), state.selectedId, generation, { opening: true })
|
||||
.finally(() => {
|
||||
if (
|
||||
generation === state.gameOpenGeneration
|
||||
&& String(state.selectedGameId || "") === String(id)
|
||||
) startSelectedGamePolling();
|
||||
) {
|
||||
startSelectedGamePolling();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
startSelectedGamePolling();
|
||||
void refreshSessionAgentMapping(session).catch((error) => console.warn("[Hockey] Mapping refresh for manual match failed:", error));
|
||||
}
|
||||
|
||||
updateMatchLoading(t("loadingMatchFinishing"));
|
||||
|
||||
Reference in New Issue
Block a user