Sockets funcionais
Deploy / Deploy (push) Successful in 1m0s Details

This commit is contained in:
JotaChina 2025-11-04 16:33:21 -03:00
parent 6961b682bd
commit 509e8fb609
12 changed files with 242 additions and 22 deletions

View File

@ -14,3 +14,5 @@ export const PIXELS_PER_BAR = 512; // 16 steps * 32px/step = 512px por compasso
// Níveis de zoom pré-definidos (fator de multiplicação) // Níveis de zoom pré-definidos (fator de multiplicação)
export const ZOOM_LEVELS = [0.25, 0.5, 1.0, 2.0, 4.0, 8.0]; export const ZOOM_LEVELS = [0.25, 0.5, 1.0, 2.0, 4.0, 8.0];
export const PORT_SOCK = 33001;

View File

@ -61,7 +61,6 @@ export async function loadProjectFromServer(fileName) {
} }
} }
// --- NENHUMA MUDANÇA DAQUI PARA BAIXO ---
// 'parseMmpContent' agora é chamado pelo 'socket.js' // 'parseMmpContent' agora é chamado pelo 'socket.js'
// quando ele recebe a ação 'LOAD_PROJECT' ou 'load_project_state'. // quando ele recebe a ação 'LOAD_PROJECT' ou 'load_project_state'.
@ -244,6 +243,56 @@ export function generateMmpFile() {
} }
} }
// Função auxiliar (pode ser movida para cá) que gera o XML a partir do appState
// Copiada de generateMmpFile/modifyAndSaveExistingMmp
function generateXmlFromState() {
if (!appState.global.originalXmlDoc) {
// Se não houver XML original, precisamos gerar um novo
// Por simplicidade, para este fix, vamos retornar o estado atual do LMMS
// mas o ideal seria gerar o XML completo (como generateNewMmp)
console.warn("Não há XML original para modificar. Usando a base atual do appState.");
// No seu caso, use o conteúdo de generateNewMmp()
return "";
}
const xmlDoc = appState.global.originalXmlDoc.cloneNode(true);
const head = xmlDoc.querySelector("head");
if (head) {
head.setAttribute("bpm", document.getElementById("bpm-input").value);
head.setAttribute("num_bars", document.getElementById("bars-input").value);
head.setAttribute("timesig_numerator", document.getElementById("compasso-a-input").value);
head.setAttribute("timesig_denominator", document.getElementById("compasso-b-input").value);
}
const bbTrackContainer = xmlDoc.querySelector('track[type="1"] > bbtrack > trackcontainer');
if (bbTrackContainer) {
bbTrackContainer.querySelectorAll('track[type="0"]').forEach(node => node.remove());
const tracksXml = appState.pattern.tracks.map((track) => createTrackXml(track)).join("");
const tempDoc = new DOMParser().parseFromString(`<root>${tracksXml}</root>`, "application/xml");
Array.from(tempDoc.documentElement.children).forEach((newTrackNode) => {
bbTrackContainer.appendChild(newTrackNode);
});
}
const serializer = new XMLSerializer();
return serializer.serializeToString(xmlDoc);
}
/**
* Envia o estado ATUAL do projeto (XML dos padrões) para o servidor
* para que ele persista a "cópia temporária" em disco/memória.
* Deve ser chamado APÓS alterações significativas no padrão (steps, tracks).
*/
export function syncPatternStateToServer() {
if (!window.ROOM_NAME) return; // Não faz nada se não estiver em sala
const currentXml = generateXmlFromState();
// NOTA: Usamos um novo tipo de ação para não confundir com o carregamento de arquivo
sendAction({
type: 'SYNC_PATTERN_STATE',
xml: currentXml
});
}
function createTrackXml(track) { function createTrackXml(track) {
if (track.patterns.length === 0) return ""; if (track.patterns.length === 0) return "";
const ticksPerStep = 12; const ticksPerStep = 12;

View File

@ -0,0 +1 @@
{"level":30,"time":1761689737230,"pid":3589288,"hostname":"ubuntu","timestamp":1761689737230,"socketId":"ASQB1EQ3W-aOnI6vAAAD","action":{"type":"AUDIO_SNAPSHOT_REQUEST","__token":"1","__senderId":"ASQB1EQ3W-aOnI6vAAAD","__senderName":"Alicer-ASQB"},"msg":"action_received"}

View File

@ -0,0 +1 @@
{"level":30,"time":1761690673639,"pid":3605182,"hostname":"ubuntu","timestamp":1761690673638,"socketId":"pCS58062xW8Axkl9AAAB","action":{"type":"AUDIO_SNAPSHOT_REQUEST","__token":"1","__senderId":"pCS58062xW8Axkl9AAAB","__senderName":"Alicer-pCS5"},"msg":"action_received"}

File diff suppressed because one or more lines are too long

View File

@ -2,3 +2,4 @@
{"level":30,"time":1761613011730,"pid":2330065,"hostname":"ubuntu","timestamp":1761613011730,"socketId":"fRRbf0JwF38jJPpsAAAD","action":{"type":"SET_SYNC_MODE","mode":"local","__token":"5","__senderId":"fRRbf0JwF38jJPpsAAAD","__senderName":"Anônimo-fRRb"},"msg":"action_received"} {"level":30,"time":1761613011730,"pid":2330065,"hostname":"ubuntu","timestamp":1761613011730,"socketId":"fRRbf0JwF38jJPpsAAAD","action":{"type":"SET_SYNC_MODE","mode":"local","__token":"5","__senderId":"fRRbf0JwF38jJPpsAAAD","__senderName":"Anônimo-fRRb"},"msg":"action_received"}
{"level":30,"time":1761613031901,"pid":2330065,"hostname":"ubuntu","timestamp":1761613031901,"socketId":"tkcFLLU39_jT51FIAAAF","action":{"type":"AUDIO_SNAPSHOT_REQUEST","__token":"1","__senderId":"tkcFLLU39_jT51FIAAAF","__senderName":"Alicer-tkcF"},"msg":"action_received"} {"level":30,"time":1761613031901,"pid":2330065,"hostname":"ubuntu","timestamp":1761613031901,"socketId":"tkcFLLU39_jT51FIAAAF","action":{"type":"AUDIO_SNAPSHOT_REQUEST","__token":"1","__senderId":"tkcFLLU39_jT51FIAAAF","__senderName":"Alicer-tkcF"},"msg":"action_received"}
{"level":30,"time":1761613034668,"pid":2330065,"hostname":"ubuntu","timestamp":1761613034668,"socketId":"tkcFLLU39_jT51FIAAAF","action":{"type":"SET_SYNC_MODE","mode":"local","__token":"2","__senderId":"tkcFLLU39_jT51FIAAAF","__senderName":"Alicer-tkcF","__syncMode":"global"},"msg":"action_received"} {"level":30,"time":1761613034668,"pid":2330065,"hostname":"ubuntu","timestamp":1761613034668,"socketId":"tkcFLLU39_jT51FIAAAF","action":{"type":"SET_SYNC_MODE","mode":"local","__token":"2","__senderId":"tkcFLLU39_jT51FIAAAF","__senderName":"Alicer-tkcF","__syncMode":"global"},"msg":"action_received"}
{"level":30,"time":1761613303975,"pid":2330065,"hostname":"ubuntu","timestamp":1761613303975,"socketId":"poGWuWRFmpwiDLzpAAAH","action":{"type":"AUDIO_SNAPSHOT_REQUEST","__token":"1","__senderId":"poGWuWRFmpwiDLzpAAAH","__senderName":"Alicer-poGW"},"msg":"action_received"}

View File

@ -0,0 +1 @@
{"level":30,"time":1762283651011,"pid":2523162,"hostname":"ubuntu","timestamp":1762283651010,"socketId":"2_HkvSElpHCinNvLAAAD","action":{"type":"AUDIO_SNAPSHOT_REQUEST","__token":"1","__senderId":"2_HkvSElpHCinNvLAAAD","__senderName":"Alicer-2_Hk"},"msg":"action_received"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,14 +1,15 @@
// server.js - VERSÃO 6 (ACK + Clock Sync + Logs Dinâmicos + Persistência Autoritativa) // server.js - VERSÃO 6 (ACK + Clock Sync + Logs Dinâmicos + Persistência Autoritativa) - HTTPS ENABLED
// ========================= // =========================
// IMPORTS PRINCIPAIS // IMPORTS PRINCIPAIS
// ========================= // =========================
const express = require("express"); const express = require("express");
const { createServer } = require("http"); const https = require("https");
const { Server } = require("socket.io"); const { Server } = require("socket.io");
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
const pino = require("pino"); const pino = require("pino");
//const { PORT_SOCK } = require("../config.js");
// ------------------------- // -------------------------
// LOGGER DINÂMICO (GERENCIADOR) // LOGGER DINÂMICO (GERENCIADOR)
@ -57,11 +58,29 @@ function getActionLoggerForRoom(roomName) {
} }
// ------------------------- // -------------------------
// Configuração do Servidor // Configuração do Servidor (HTTPS)
// ------------------------- // -------------------------
const app = express(); const app = express();
const httpServer = createServer(app); const PORT = process.env.PORT || 33001;
const PORT = process.env.PORT || 33007;
// ====== HTTPS (Opção B) ======
const CERT_FULLCHAIN = process.env.SSL_FULLCHAIN || "/etc/letsencrypt/live/alice.ufsj.edu.br/fullchain.pem";
const CERT_PRIVKEY = process.env.SSL_PRIVKEY || "/etc/letsencrypt/live/alice.ufsj.edu.br/privkey.pem";
if (!fs.existsSync(CERT_FULLCHAIN) || !fs.existsSync(CERT_PRIVKEY)) {
console.error("[HTTPS] Certificados não encontrados.\n" +
` fullchain: ${CERT_FULLCHAIN}\n` +
` privkey : ${CERT_PRIVKEY}\n` +
"Defina SSL_FULLCHAIN/SSL_PRIVKEY ou instale os certificados no caminho padrão.");
process.exit(1);
}
const httpsOptions = {
cert: fs.readFileSync(CERT_FULLCHAIN),
key : fs.readFileSync(CERT_PRIVKEY),
};
const httpsServer = https.createServer(httpsOptions, app);
// ------------------------- // -------------------------
// Persistência por sala // Persistência por sala
@ -128,15 +147,11 @@ function saveRoom(roomName) {
// ------------------------- // -------------------------
// Server / IO // Server / IO
// ------------------------- // -------------------------
const io = new Server(httpServer, { const io = new Server(httpsServer, {
cors: { cors: {
origin: [ // CORREÇÃO: Simplificado para a origem real do cliente, que é onde o HTML é servido.
"https://alice.ufsj.edu.br", // O cliente provavelmente é servido a partir de https://alice.ufsj.edu.br (porta 443).
"http://127.0.0.1:33007", origin: "https://alice.ufsj.edu.br",
"http://localhost:33007",
"http://localhost:5173",
"http://127.0.0.1:5173",
],
methods: ["GET", "POST"], methods: ["GET", "POST"],
credentials: true, credentials: true,
}, },
@ -509,6 +524,7 @@ app.get("/", (req, res) => {
); );
}); });
httpServer.listen(PORT, () => { // ====== START ======
console.log(`Servidor escutando na porta http://localhost:${PORT}`); httpsServer.listen(PORT, () => {
console.log(`Servidor escutando na porta https://localhost:${PORT}`);
}); });

View File

@ -1,6 +1,6 @@
// js/socket.js — V5.5 (Toast para Sync Mode) // js/socket.js — V5.5 (Toast para Sync Mode)
// ----------------------------------------------------------------------------- // -------------------relómm------------------------------------------------------
// IMPORTS & STATE // IMPORTS & STATE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
import { appState, resetProjectState } from "./state.js"; import { appState, resetProjectState } from "./state.js";
@ -36,6 +36,7 @@ import {
import { parseMmpContent } from "./file.js"; import { parseMmpContent } from "./file.js";
import { renderAll, showToast } from "./ui.js"; // showToast() import { renderAll, showToast } from "./ui.js"; // showToast()
import { updateStepUI, renderPatternEditor } from "./pattern/pattern_ui.js"; import { updateStepUI, renderPatternEditor } from "./pattern/pattern_ui.js";
import { PORT_SOCK } from "./config.js";
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Gera um ID único otimista (ex: "track_1678886401000_abc123") // Gera um ID único otimista (ex: "track_1678886401000_abc123")
@ -49,7 +50,7 @@ function generateUniqueId(prefix = "item") {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// CONFIGURAÇÃO DO SOCKET.IO // CONFIGURAÇÃO DO SOCKET.IO
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
const socket = io("http://localhost:33007", { const socket = io(`https://alice.ufsj.edu.br:${PORT_SOCK}`, {
transports: ["websocket", "polling"], transports: ["websocket", "polling"],
withCredentials: true, withCredentials: true,
}); });