diff --git a/assets/js/creations/config.js b/assets/js/creations/config.js index b7a5a2c..05d4d5f 100644 --- a/assets/js/creations/config.js +++ b/assets/js/creations/config.js @@ -13,4 +13,6 @@ export const PIXELS_PER_STEP = 32; // Cada step (1/16) terá 32px de largura export const PIXELS_PER_BAR = 512; // 16 steps * 32px/step = 512px por compasso (bar) // 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]; \ No newline at end of file +export const ZOOM_LEVELS = [0.25, 0.5, 1.0, 2.0, 4.0, 8.0]; + +export const PORT_SOCK = 33001; \ No newline at end of file diff --git a/assets/js/creations/file.js b/assets/js/creations/file.js index 79acc0b..1c2ded8 100644 --- a/assets/js/creations/file.js +++ b/assets/js/creations/file.js @@ -61,7 +61,6 @@ export async function loadProjectFromServer(fileName) { } } -// --- NENHUMA MUDANÇA DAQUI PARA BAIXO --- // 'parseMmpContent' agora é chamado pelo 'socket.js' // 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(`${tracksXml}`, "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) { if (track.patterns.length === 0) return ""; const ticksPerStep = 12; diff --git a/assets/js/creations/server/server.js b/assets/js/creations/server/server.js index d8e62cf..e545654 100644 --- a/assets/js/creations/server/server.js +++ b/assets/js/creations/server/server.js @@ -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 // ========================= const express = require("express"); -const { createServer } = require("http"); +const https = require("https"); const { Server } = require("socket.io"); const fs = require("fs"); const path = require("path"); const pino = require("pino"); +//const { PORT_SOCK } = require("../config.js"); // ------------------------- // LOGGER DINÂMICO (GERENCIADOR) @@ -57,11 +58,29 @@ function getActionLoggerForRoom(roomName) { } // ------------------------- -// Configuração do Servidor +// Configuração do Servidor (HTTPS) // ------------------------- const app = express(); -const httpServer = createServer(app); -const PORT = process.env.PORT || 33007; +const PORT = process.env.PORT || 33001; + +// ====== 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 @@ -126,17 +145,13 @@ function saveRoom(roomName) { } // ------------------------- -// Server / IO +// Server / IO // ------------------------- -const io = new Server(httpServer, { +const io = new Server(httpsServer, { cors: { - origin: [ - "https://alice.ufsj.edu.br", - "http://127.0.0.1:33007", - "http://localhost:33007", - "http://localhost:5173", - "http://127.0.0.1:5173", - ], + // CORREÇÃO: Simplificado para a origem real do cliente, que é onde o HTML é servido. + // O cliente provavelmente é servido a partir de https://alice.ufsj.edu.br (porta 443). + origin: "https://alice.ufsj.edu.br", methods: ["GET", "POST"], credentials: true, }, @@ -509,6 +524,7 @@ app.get("/", (req, res) => { ); }); -httpServer.listen(PORT, () => { - console.log(`Servidor escutando na porta http://localhost:${PORT}`); -}); +// ====== START ====== +httpsServer.listen(PORT, () => { + console.log(`Servidor escutando na porta https://localhost:${PORT}`); +}); \ No newline at end of file diff --git a/assets/js/creations/socket.js b/assets/js/creations/socket.js index 5530825..0456b1a 100644 --- a/assets/js/creations/socket.js +++ b/assets/js/creations/socket.js @@ -1,6 +1,6 @@ // js/socket.js — V5.5 (Toast para Sync Mode) -// ----------------------------------------------------------------------------- +// -------------------relómm------------------------------------------------------ // IMPORTS & STATE // ----------------------------------------------------------------------------- import { appState, resetProjectState } from "./state.js"; @@ -36,6 +36,7 @@ import { import { parseMmpContent } from "./file.js"; import { renderAll, showToast } from "./ui.js"; // showToast() import { updateStepUI, renderPatternEditor } from "./pattern/pattern_ui.js"; +import { PORT_SOCK } from "./config.js"; // ----------------------------------------------------------------------------- // Gera um ID único otimista (ex: "track_1678886401000_abc123") @@ -49,7 +50,7 @@ function generateUniqueId(prefix = "item") { // ----------------------------------------------------------------------------- // CONFIGURAÇÃO DO SOCKET.IO // ----------------------------------------------------------------------------- -const socket = io("http://localhost:33007", { +const socket = io(`https://alice.ufsj.edu.br:${PORT_SOCK}`, { transports: ["websocket", "polling"], withCredentials: true, });