testando medida de latencia

This commit is contained in:
JotaChina committed 2026-02-24 18:37:46 -03:00
1 parent 2a086e84a0
commit 1aafe3080d
4 files changed
+239 -4634543

No files matched your search

+149 -21
View File
@@ -50,6 +50,42 @@ import { updateStepUI, renderPatternEditor } from "./pattern/pattern_ui.js";
import { PORT_SOCK } from "./config.js";
import { DEFAULT_PROJECT_XML } from "./utils.js"
// --- NO TOPO DO SEU socket.js ---
export let USER_NAME = null;
export let currentRoom = null;
let roomSeq = 0;
let lastActionToken = 0;
let isOfflineMode = false;
// --- FUNÇÃO DE AUTENTICAÇÃO INTELIGENTE ---
export async function getOrFetchUsername() {
// Se já pegamos o nome antes, não pede de novo
if (USER_NAME) return USER_NAME;
try {
const res = await fetch('/api/check_auth', { credentials: 'include' });
const data = await res.json();
if (data.logged_in) {
USER_NAME = data.user;
return USER_NAME;
}
} catch (e) {
console.warn("API de Auth indisponível, caindo para modo visitante.");
}
// Se não estiver logado, barra a tela e pede apelido
let name = prompt("Você não está logado. Digite seu apelido para entrar na DAW Online:");
if (!name || name.trim() === "") {
name = "Produtor_" + Math.floor(Math.random() * 1000);
}
USER_NAME = name.trim();
return USER_NAME;
}
// --- TELEMETRIA PARA A DISSERTAÇÃO ---
window.jamTelemetry = [];
let lastReceivedSeq = 0;
function _getRackIdFallback() {
// 1) pega do primeiro bassline que já tenha instrumentSourceId
const b = (appState.pattern.tracks || []).find(
@@ -101,8 +137,7 @@ const socket = io(`https://alice.ufsj.edu.br:${PORT_SOCK}`, {
withCredentials: true,
});
let USER_NAME = `Alicer-${Math.floor(Math.random() * 9999)}`;
let currentRoom = null;
// -------------------------------------
// -----------------------------------------------------------------------------
// CLOCK SYNC — Sincroniza relógio cliente-servidor
@@ -177,27 +212,45 @@ export function sendActionSafe(action) {
// -----------------------------------------------------------------------------
// CONEXÃO / JOIN / LOGS
// -----------------------------------------------------------------------------
socket.on("connect", () => {
console.log(`Conectado ao servidor com ID: ${socket.id}`);
showToast("✅ Conectado ao servidor", "success");
if (USER_NAME.startsWith("Alicer-")) {
USER_NAME = `Alicer-${socket.id.substring(0, 4)}`;
}
const urlRoom = new URLSearchParams(window.location.search).get("room");
currentRoom = urlRoom || null;
if (currentRoom) {
console.log(`Modo Online. Sala detectada: ${currentRoom}`);
// --- MONITORAMENTO DE PRESENÇA ---
socket.on("room_status", (data) => {
console.log(
`%c[MONITOR DE SALA] 👥 ${data.count} pessoa(s) na sala '${data.room}'`,
'background: #222; color: #bada55; font-size: 16px; font-weight: bold; padding: 4px;'
);
console.log("IDs conectados:", data.users);
// Se quiser um aviso visual na tela da DAW:
if(data.count > 1) {
showToast(`👥 Agora há ${data.count} produtores na sala!`, "success");
}
});
// ---------------------------------
// --- SUBSTITUA SEU socket.on("connect") POR ESTE ---
socket.on("connect", async () => {
console.log(`Conectado ao servidor com ID: ${socket.id}`);
const urlRoom = new URLSearchParams(window.location.search).get("room");
if (urlRoom) {
currentRoom = urlRoom;
console.log(`Modo Online. Sala detectada na URL: ${currentRoom}`);
showToast(`🎧 Conectado à sala ${currentRoom}`, "info");
// Mostra o botão se estiver online
const syncModeBtn = document.getElementById("sync-mode-btn");
//if (syncModeBtn) syncModeBtn.style.display = ""; // Garante visibilidade
// Como tem sala na URL, EXIGE o login/apelido agora
const myName = await getOrFetchUsername();
socket.emit("join_room", {
roomName: currentRoom,
userName: myName
});
} else {
console.log("Modo Local. Conectado, mas não em uma sala.");
// Entrou na DAW pura, não pede nada ainda.
console.log("Modo Local. Aguardando criação de sala.");
showToast("🔌 Modo local (fora de sala)", "warning");
// Esconde se offline
const syncModeBtn = document.getElementById("sync-mode-btn");
//if (syncModeBtn) syncModeBtn.style.display = "none";
}
syncServerTime();
@@ -238,16 +291,18 @@ socket.on("system_update", (data) => {
socket.on("load_project_state", async (projectXml) => {
console.log("Recebendo estado salvo da sala...");
showToast("🔄 Recebendo estado atual da sala...", "info", 4000);
if (isLoadingProject) return;
isLoadingProject = true;
try {
// 1. Carrega o XML que veio do servidor (pode estar desatualizado)
await parseMmpContent(projectXml);
// 🔥 CORREÇÃO: Força a restauração da sessão LOCAL logo após carregar o XML
// Isso garante que suas alterações locais (BPM, steps) "ganhem" do servidor
if (window.ROOM_NAME) {
const raw = sessionStorage.getItem(`temp_state_${window.ROOM_NAME}`);
if (currentRoom) {
const raw = sessionStorage.getItem(`temp_state_${currentRoom}`);
if (raw) {
// Se existe 'raw', confiamos que é o estado mais recente do usuário.
console.log("Re-aplicando sessão local (mesmo se vazia)...");
@@ -256,6 +311,7 @@ socket.on("load_project_state", async (projectXml) => {
}
renderAll();
saveStateToSession();
showToast("🎵 Projeto carregado com sucesso", "success");
const hasAudio =
@@ -357,6 +413,8 @@ export function sendAction(action) {
const token = (++lastActionToken).toString();
action.__token = token;
// Usa o relógio sincronizado com o servidor
action.__send_time = Date.now() + serverOffsetMs;
action.__senderId = socket.id;
action.__senderName = USER_NAME;
@@ -537,6 +595,42 @@ socket.on("feedback", (msg) => {
socket.on("action_broadcast", (payload) => {
const action = payload && payload.type ? payload : payload?.action || payload;
// --- INÍCIO DA COLETA DE DADOS ---
const receiveTime = Date.now() + serverOffsetMs;
// 1. Calcula a latência (se foi outro usuário que mandou)
let latencyMs = 0;
if (action.__send_time && action.userId !== socket.id) {
latencyMs = receiveTime - action.__send_time;
}
// 2. Verifica a Ordem dos Pacotes (Jitter/Perda)
let isOutOfOrder = false;
let missingPackets = 0;
if (action.__seq) {
if (lastReceivedSeq !== 0 && action.__seq !== lastReceivedSeq + 1) {
isOutOfOrder = true;
missingPackets = Math.abs(action.__seq - lastReceivedSeq) - 1;
}
lastReceivedSeq = action.__seq;
}
// 3. Salva no array se não for a sua própria mensagem voltando
// TRAVA DE SEGURANÇA: Se o array não existir ainda, cria na hora!
window.jamTelemetry = window.jamTelemetry || [];
if (action.userId !== socket.id) {
window.jamTelemetry.push({
type: action.type,
seq: action.__seq,
latency_ms: latencyMs.toFixed(2),
out_of_order: isOutOfOrder,
missing_packets: missingPackets,
timestamp: new Date().toISOString()
});
}
// --- FIM DA COLETA DE DADOS ---
if (action && action.__token) {
processedTokens.add(action.__token);
if (lastBroadcastTimeout && pendingToken === action.__token) {
@@ -1608,5 +1702,39 @@ async function handleActionBroadcast(action) {
}
}
// ============================================================================
// RECUPERAÇÃO DE ESTADO (TAB SLEEP / WAKE UP)
// ============================================================================
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "visible") {
console.log("%c[SISTEMA] Aba reativada! Solicitando estado...", "color: #00ff00; background: #222; padding: 4px;");
// Usa o currentRoom oficial
if (socket.connected && currentRoom) {
// Deleta o cache local velho
sessionStorage.removeItem(`temp_state_${currentRoom}`);
// Pede o estado fresquinho
socket.emit("request_full_sync", { room: currentRoom });
showToast("🔄 Sincronizando com a sala...", "info");
}
}
});
// ============================================================================
// NOTIFICAÇÕES DE PRESENÇA NA SALA
// ============================================================================
socket.on("user_joined", ({ username }) => {
// Toca um sonzinho rápido e mostra o popup verde
showToast(`👋 ${username} entrou na sala!`, "success", 4000);
console.log(`[PRESENÇA] ${username} conectou-se.`);
});
socket.on("user_left", ({ username }) => {
// Mostra o popup amarelo de aviso
showToast(`🏃 ${username} saiu da sala.`, "warning", 4000);
console.log(`[PRESENÇA] ${username} desconectou-se.`);
});
// EXPORTS
export { socket };