const { Telnet } = require('telnet-client'); const net = require('net'); class FiberhomeManager { constructor() { this.tl1Connection = null; this.commandId = 1; // Configuração apenas para UNM2000 via TL1 this.config = { unm2000: { host: '131.0.192.9', port: 3337, username: '1', password: '1', timeout: 15000 } }; this.logger = require('../utils/logger'); } /** * Testar conectividade de rede com um host */ async testarConectividade(host, port, timeout = 5000) { return new Promise((resolve) => { const socket = new net.Socket(); socket.setTimeout(timeout); socket.connect(port, host, () => { this.logger.debug(`Conectividade OK: ${host}:${port}`); socket.destroy(); resolve(true); }); socket.on('error', (error) => { this.logger.debug(`Erro de conectividade ${host}:${port}:`, error.message); resolve(false); }); socket.on('timeout', () => { this.logger.debug(`Timeout de conectividade ${host}:${port}`); socket.destroy(); resolve(false); }); }); } /** * Conectar à OLT via Telnet */ async conectarOLT() { try { if (this.telnetConnection && this.telnetConnection.getSocket()) { this.logger.debug('Conexão OLT já existe, reutilizando'); return true; } // Primeiro, testar conectividade básica this.logger.debug('Testando conectividade com OLT...'); const conectividade = await this.testarConectividade( this.config.olt.host, this.config.olt.port, 5000 ); if (!conectividade) { throw new Error(`Não foi possível conectar ao host ${this.config.olt.host}:${this.config.olt.port}`); } this.logger.debug('Conectando à OLT Fiberhome', this.config.olt); this.telnetConnection = new Telnet(); const params = { host: this.config.olt.host, port: this.config.olt.port, shellPrompt: this.config.olt.shellPrompt, timeout: this.config.olt.timeout, loginPrompt: /Username:|login:/i, passwordPrompt: /Password:|password:/i, username: this.config.olt.username, password: this.config.olt.password, echoLines: 1, debug: true }; this.logger.debug('Tentando conectar com parâmetros:', { host: params.host, port: params.port, username: params.username, timeout: params.timeout }); await this.telnetConnection.connect(params); // Aguardar o prompt aparecer await new Promise(resolve => setTimeout(resolve, 2000)); this.logger.info('Conectado à OLT Fiberhome com sucesso'); return true; } catch (error) { this.logger.error('Erro ao conectar à OLT', { error: error.message, host: this.config.olt.host, port: this.config.olt.port, stack: error.stack }); // Limpar conexão com erro if (this.telnetConnection) { try { this.telnetConnection.end(); } catch (e) { // Ignorar erros ao fechar conexão inválida } this.telnetConnection = null; } return false; } } /** * Conectar ao UNM2000 via TL1 */ async conectarUNM2000() { try { if (this.tl1Connection && !this.tl1Connection.destroyed) { this.logger.debug('Conexão TL1 já existe e está ativa'); return true; } this.logger.debug('Conectando ao UNM2000 via TL1', this.config.unm2000); return new Promise((resolve, reject) => { this.tl1Connection = new net.Socket(); let authenticated = false; let dataBuffer = ''; this.tl1Connection.setTimeout(this.config.unm2000.timeout); // Handler para dados recebidos this.tl1Connection.on('data', (data) => { dataBuffer += data.toString(); this.logger.debug('TL1 dados recebidos:', dataBuffer); // Verificar se login foi bem-sucedido if (!authenticated && dataBuffer.includes('COMPLD')) { authenticated = true; this.logger.info('Login TL1 bem-sucedido'); resolve(true); } }); this.tl1Connection.connect(this.config.unm2000.port, this.config.unm2000.host, () => { this.logger.debug('Socket TL1 conectado, enviando comando de login'); // Comando de login TL1 const loginCommand = `ACT-USER::${this.config.unm2000.username}:${this.commandId++}::${this.config.unm2000.password};`; this.tl1Connection.write(loginCommand + '\r\n'); // Timeout para autenticação setTimeout(() => { if (!authenticated) { this.logger.error('Timeout na autenticação TL1'); reject(new Error('Timeout na autenticação TL1')); } }, 10000); }); this.tl1Connection.on('error', (error) => { this.logger.error('Erro na conexão TL1', error); reject(error); }); this.tl1Connection.on('timeout', () => { this.logger.error('Timeout na conexão TL1'); reject(new Error('Timeout na conexão TL1')); }); this.tl1Connection.on('close', () => { this.logger.debug('Conexão TL1 fechada'); this.tl1Connection = null; }); }); } catch (error) { this.logger.error('Erro ao conectar UNM2000', error); return false; } } this.logger.error('Timeout na conexão UNM2000'); reject(new Error('Timeout na conexão')); }); }); } catch (error) { this.logger.error('Erro ao conectar ao UNM2000', error); return false; } } /** * Executar comando na OLT */ async executarComandoOLT(comando) { try { if (!this.telnetConnection) { const conectado = await this.conectarOLT(); if (!conectado) { throw new Error('Não foi possível conectar à OLT'); } } this.logger.debug('Executando comando OLT', { comando }); const resultado = await this.telnetConnection.exec(comando); this.logger.debug('Resultado do comando OLT', { comando, resultadoLength: resultado.length }); return resultado; } catch (error) { this.logger.error('Erro ao executar comando na OLT', { comando, error: error.message }); throw error; } } /** * Executar comando TL1 no UNM2000 */ async executarComandoTL1(comando) { try { if (!this.tl1Connection || this.tl1Connection.destroyed) { const conectado = await this.conectarUNM2000(); if (!conectado) { throw new Error('Não foi possível conectar ao UNM2000'); } } this.logger.debug('Executando comando TL1', { comando }); return new Promise((resolve, reject) => { let resposta = ''; const timeout = setTimeout(() => { reject(new Error('Timeout na execução do comando TL1')); }, 10000); const onData = (data) => { resposta += data.toString(); // Verificar se a resposta está completa (termina com ;) if (resposta.includes(';')) { clearTimeout(timeout); this.tl1Connection.off('data', onData); this.logger.debug('Resposta TL1 recebida', { comando, respostaLength: resposta.length }); resolve(resposta); } }; this.tl1Connection.on('data', onData); this.tl1Connection.write(comando + '\r\n'); }); } catch (error) { this.logger.error('Erro ao executar comando TL1', { comando, error: error.message }); throw error; } } /** * Obter status da ONU por serial */ async obterStatusONU(serial) { try { this.logger.debug('Obtendo status da ONU', { serial }); // Primeiro, encontrar a ONU pelo serial const comandoBusca = `show ont info serial ${serial}`; const resultadoBusca = await this.executarComandoOLT(comandoBusca); if (!resultadoBusca || resultadoBusca.includes('No such ont')) { return { success: false, error: 'ONU não encontrada', serial }; } // Extrair informações básicas da ONU const infoONU = this.extrairInfoONU(resultadoBusca); if (!infoONU.slot || !infoONU.pon || !infoONU.onuId) { return { success: false, error: 'Não foi possível extrair informações da ONU', serial }; } // Obter status detalhado const comandoStatus = `show ont info ${infoONU.slot} ${infoONU.pon} ${infoONU.onuId}`; const resultadoStatus = await this.executarComandoOLT(comandoStatus); // Obter informações de sinal const comandoSinal = `show ont optical-info ${infoONU.slot} ${infoONU.pon} ${infoONU.onuId}`; const resultadoSinal = await this.executarComandoOLT(comandoSinal); // Obter status das portas Ethernet const comandoPortas = `show ont port state ${infoONU.slot} ${infoONU.pon} ${infoONU.onuId} eth all`; const resultadoPortas = await this.executarComandoOLT(comandoPortas); // Obter configurações WAN const comandoWAN = `show ont wan-info ${infoONU.slot} ${infoONU.pon} ${infoONU.onuId}`; const resultadoWAN = await this.executarComandoOLT(comandoWAN); const status = this.processarStatusONU({ info: resultadoStatus, sinal: resultadoSinal, portas: resultadoPortas, wan: resultadoWAN, ...infoONU }); return { success: true, serial, ...status }; } catch (error) { this.logger.error('Erro ao obter status da ONU', { serial, error: error.message }); return { success: false, error: error.message, serial }; } } /** * Obter status da ONU por device name */ async obterStatusONUPorNome(deviceName) { try { this.logger.debug('Obtendo status da ONU por nome', { deviceName }); // Buscar ONU pelo device name const comandoBusca = `show ont info summary | grep "${deviceName}"`; const resultadoBusca = await this.executarComandoOLT(comandoBusca); if (!resultadoBusca || resultadoBusca.trim() === '') { return { success: false, error: 'ONU não encontrada pelo device name', deviceName }; } // Extrair serial do resultado const serial = this.extrairSerialDoNome(resultadoBusca); if (!serial) { return { success: false, error: 'Não foi possível extrair o serial da ONU', deviceName }; } // Usar o método de busca por serial const resultado = await this.obterStatusONU(serial); resultado.deviceName = deviceName; return resultado; } catch (error) { this.logger.error('Erro ao obter status da ONU por nome', { deviceName, error: error.message }); return { success: false, error: error.message, deviceName }; } } /** * Extrair informações básicas da ONU do resultado da busca */ extrairInfoONU(resultado) { const linhas = resultado.split('\n'); const info = {}; for (const linha of linhas) { // Buscar padrão: gpon_olt-1/1/1:1 const matchSlotPon = linha.match(/gpon_olt-(\d+)\/(\d+)\/(\d+):(\d+)/); if (matchSlotPon) { info.slot = matchSlotPon[1]; info.board = matchSlotPon[2]; info.pon = matchSlotPon[3]; info.onuId = matchSlotPon[4]; } // Buscar outros dados relevantes if (linha.includes('Serial number:')) { info.serial = linha.split(':')[1]?.trim(); } if (linha.includes('Device name:')) { info.deviceName = linha.split(':')[1]?.trim(); } } return info; } /** * Extrair serial do device name */ extrairSerialDoNome(resultado) { const linhas = resultado.split('\n'); for (const linha of linhas) { // Buscar padrão com serial number const match = linha.match(/([A-Z0-9]{12})/); if (match) { return match[1]; } } return null; } /** * Processar status detalhado da ONU */ processarStatusONU(dados) { const status = { slot: dados.slot, pon: dados.pon, onuId: dados.onuId, deviceName: dados.deviceName || 'N/A', online: false, rxPower: 'N/A', txPower: 'N/A', distance: 'N/A', portasEthernet: [], servicosWAN: [] }; // Processar status online/offline if (dados.info) { status.online = dados.info.includes('online') || dados.info.includes('working'); } // Processar informações de sinal if (dados.sinal) { const linhas = dados.sinal.split('\n'); for (const linha of linhas) { if (linha.includes('Rx power')) { const match = linha.match(/([-+]?\d+\.?\d*)/); if (match) status.rxPower = match[1] + ' dBm'; } if (linha.includes('Tx power')) { const match = linha.match(/([-+]?\d+\.?\d*)/); if (match) status.txPower = match[1] + ' dBm'; } if (linha.includes('Distance')) { const match = linha.match(/(\d+)/); if (match) status.distance = match[1] + ' m'; } } } // Processar status das portas Ethernet if (dados.portas) { const linhas = dados.portas.split('\n'); for (const linha of linhas) { const match = linha.match(/eth\s+(\d+)\s+(\w+)/); if (match) { status.portasEthernet.push({ porta: match[1], status: match[2] }); } } } // Processar serviços WAN if (dados.wan) { const linhas = dados.wan.split('\n'); for (const linha of linhas) { if (linha.includes('Service')) { const servicoMatch = linha.match(/Service\s+(\d+).*?(\w+).*?(\d+\.\d+\.\d+\.\d+)?/); if (servicoMatch) { status.servicosWAN.push({ id: servicoMatch[1], status: servicoMatch[2], ip: servicoMatch[3] || 'N/A' }); } } } } return status; } /** * Desconectar todas as conexões */ async desconectar() { try { if (this.telnetConnection) { await this.telnetConnection.end(); this.telnetConnection = null; this.logger.debug('Conexão OLT encerrada'); } if (this.tl1Connection && !this.tl1Connection.destroyed) { this.tl1Connection.destroy(); this.tl1Connection = null; this.logger.debug('Conexão UNM2000 encerrada'); } } catch (error) { this.logger.error('Erro ao desconectar', error); } } /** * Verificar se as conexões estão ativas */ verificarConexoes() { return { olt: this.telnetConnection && this.telnetConnection.getSocket(), unm2000: this.tl1Connection && !this.tl1Connection.destroyed }; } /** * Diagnóstico completo de conectividade */ async diagnosticarConectividade() { const diagnostico = { olt: { host: this.config.olt.host, port: this.config.olt.port, conectividade: false, telnet: false, erro: null }, unm2000: { host: this.config.unm2000.host, port: this.config.unm2000.port, conectividade: false, tl1: false, erro: null } }; // Testar OLT try { this.logger.debug('Testando conectividade OLT...'); diagnostico.olt.conectividade = await this.testarConectividade( this.config.olt.host, this.config.olt.port ); if (diagnostico.olt.conectividade) { this.logger.debug('Testando login Telnet OLT...'); diagnostico.olt.telnet = await this.conectarOLT(); } } catch (error) { diagnostico.olt.erro = error.message; this.logger.error('Erro no diagnóstico OLT:', error); } // Testar UNM2000 try { this.logger.debug('Testando conectividade UNM2000...'); diagnostico.unm2000.conectividade = await this.testarConectividade( this.config.unm2000.host, this.config.unm2000.port ); if (diagnostico.unm2000.conectividade) { this.logger.debug('Testando login TL1 UNM2000...'); diagnostico.unm2000.tl1 = await this.conectarUNM2000(); } } catch (error) { diagnostico.unm2000.erro = error.message; this.logger.error('Erro no diagnóstico UNM2000:', error); } return diagnostico; } } module.exports = FiberhomeManager;