617 lines
20 KiB
JavaScript
617 lines
20 KiB
JavaScript
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;
|