UNPKG

php-universal-mcp-server

Version:

Servidor MCP universal para desenvolvimento PHP e criação de sites em qualquer provedor de hospedagem

297 lines (265 loc) 8.65 kB
/** * Site Creator - Módulo para criação de sites a partir de templates */ const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); class SiteCreator { /** * Inicializa o criador de sites * @param {Object} config - Configurações */ constructor(config = {}) { this.config = { templatesDir: path.join(__dirname, '../templates'), sitesDir: config.sitesDir || path.join(process.cwd(), 'sites'), ...config }; // Criar diretório de sites se não existir if (!fs.existsSync(this.config.sitesDir)) { fs.mkdirSync(this.config.sitesDir, { recursive: true }); } } /** * Lista os templates disponíveis * @returns {Array<string>} Lista de nomes de templates */ listTemplates() { try { return fs.readdirSync(this.config.templatesDir) .filter(item => { const stats = fs.statSync(path.join(this.config.templatesDir, item)); return stats.isDirectory(); }); } catch (error) { console.error('Erro ao listar templates:', error.message); return []; } } /** * Verifica se um template existe * @param {string} templateName - Nome do template * @returns {boolean} Verdadeiro se o template existir */ templateExists(templateName) { const templatePath = path.join(this.config.templatesDir, templateName); return fs.existsSync(templatePath) && fs.statSync(templatePath).isDirectory(); } /** * Cria um novo site a partir de um template * @param {Object} options - Opções de criação * @param {string} options.domain - Nome do domínio * @param {string} options.template - Nome do template * @param {string} options.siteName - Nome do site * @param {Object} options.variables - Variáveis para substituir no template * @returns {Object} Resultado da criação */ createSite(options) { const { domain, template = 'default', siteName, variables = {} } = options; // Validações if (!domain) { return { success: false, error: 'Domínio não especificado', timestamp: new Date().toISOString() }; } if (!this.templateExists(template)) { return { success: false, error: `Template '${template}' não encontrado`, timestamp: new Date().toISOString() }; } const siteDir = path.join(this.config.sitesDir, domain); // Verifica se o site já existe if (fs.existsSync(siteDir)) { return { success: false, error: `Site '${domain}' já existe`, timestamp: new Date().toISOString() }; } try { // Cria o diretório do site fs.mkdirSync(siteDir, { recursive: true }); // Copia o template para o diretório do site this._copyTemplate(template, siteDir, { siteName: siteName || domain, ...variables }); // Cria o arquivo de configuração do site const configFile = path.join(siteDir, 'site-config.json'); fs.writeFileSync(configFile, JSON.stringify({ domain, template, siteName: siteName || domain, createdAt: new Date().toISOString(), variables: { siteName: siteName || domain, ...variables } }, null, 2), 'utf8'); // Retorna sucesso return { success: true, domain, template, siteName: siteName || domain, siteDir, message: `Site '${domain}' criado com sucesso!`, timestamp: new Date().toISOString() }; } catch (error) { // Remove o diretório do site em caso de erro if (fs.existsSync(siteDir)) { this._removeDirectory(siteDir); } return { success: false, error: `Erro ao criar site: ${error.message}`, timestamp: new Date().toISOString() }; } } /** * Copia um template para o diretório do site * @param {string} templateName - Nome do template * @param {string} siteDir - Diretório do site * @param {Object} variables - Variáveis para substituir no template * @private */ _copyTemplate(templateName, siteDir, variables) { const templateDir = path.join(this.config.templatesDir, templateName); this._copyDirectory(templateDir, siteDir, variables); } /** * Copia um diretório recursivamente * @param {string} sourceDir - Diretório fonte * @param {string} targetDir - Diretório destino * @param {Object} variables - Variáveis para substituir no conteúdo * @private */ _copyDirectory(sourceDir, targetDir, variables) { // Cria o diretório destino se não existir if (!fs.existsSync(targetDir)) { fs.mkdirSync(targetDir, { recursive: true }); } // Lista os arquivos e diretórios const items = fs.readdirSync(sourceDir); // Copia cada item for (const item of items) { const sourcePath = path.join(sourceDir, item); const targetPath = path.join(targetDir, item); const stats = fs.statSync(sourcePath); if (stats.isDirectory()) { // Se for diretório, copia recursivamente this._copyDirectory(sourcePath, targetPath, variables); } else { // Se for arquivo, copia com substituição de variáveis this._copyFile(sourcePath, targetPath, variables); } } } /** * Copia um arquivo com substituição de variáveis * @param {string} sourcePath - Caminho do arquivo fonte * @param {string} targetPath - Caminho do arquivo destino * @param {Object} variables - Variáveis para substituir no conteúdo * @private */ _copyFile(sourcePath, targetPath, variables) { let content = fs.readFileSync(sourcePath, 'utf8'); // Substitui as variáveis no conteúdo for (const [key, value] of Object.entries(variables)) { content = content.replace(new RegExp(`\\{\\{\\s*${key}\\s*\\}\\}`, 'g'), value); } // Escreve o arquivo com as substituições fs.writeFileSync(targetPath, content, 'utf8'); } /** * Remove um diretório recursivamente * @param {string} dir - Diretório a ser removido * @private */ _removeDirectory(dir) { if (fs.existsSync(dir)) { fs.rmSync(dir, { recursive: true, force: true }); } } /** * Lista os sites criados * @returns {Array<Object>} Lista de sites */ listSites() { try { return fs.readdirSync(this.config.sitesDir) .filter(item => { const stats = fs.statSync(path.join(this.config.sitesDir, item)); return stats.isDirectory(); }) .map(domain => { const configPath = path.join(this.config.sitesDir, domain, 'site-config.json'); if (fs.existsSync(configPath)) { try { return JSON.parse(fs.readFileSync(configPath, 'utf8')); } catch (e) { return { domain }; } } return { domain }; }); } catch (error) { console.error('Erro ao listar sites:', error.message); return []; } } /** * Inicia um servidor local para o site * @param {string} domain - Nome do domínio * @param {number} port - Porta do servidor * @returns {Object} Resultado da operação */ startServer(domain, port = 8000) { const siteDir = path.join(this.config.sitesDir, domain); if (!fs.existsSync(siteDir)) { return { success: false, error: `Site '${domain}' não encontrado`, timestamp: new Date().toISOString() }; } try { // Verifica se o PHP está instalado try { execSync('php -v', { stdio: 'ignore' }); } catch (e) { return { success: false, error: 'PHP não disponível no sistema. Instale o PHP para iniciar o servidor.', timestamp: new Date().toISOString() }; } // Inicia o servidor PHP const serverProcess = execSync( `php -S localhost:${port} -t "${siteDir}"`, { stdio: 'pipe', detached: true } ); return { success: true, domain, port, url: `http://localhost:${port}`, message: `Servidor iniciado para '${domain}' em http://localhost:${port}`, timestamp: new Date().toISOString() }; } catch (error) { return { success: false, error: `Erro ao iniciar servidor: ${error.message}`, timestamp: new Date().toISOString() }; } } } module.exports = SiteCreator;