ipoe: fluxo adicionado

Signed-off-by: Rodrigo Martins <rodrigo@martinsevieira.adv.br>
This commit is contained in:
Rodrigo Martins committed 2026-04-05 09:34:17 -03:00
1 parent 1427e6126a
commit ef6f94067b
5 files changed
+8791 -8457

No files matched your search

+8513 -8422
View File
File diff suppressed because it is too large. Load diff
+72
View File
@@ -884,6 +884,78 @@ class FiberhomeManager {
return diagnostico; return diagnostico;
} }
/**
* Configura IPoE em ONU FiberHome: SET-WANSERVICE com VLAN 977
* Busca a ONU registrada pela serial e reconfigura as portas WAN
* @param {string} serial - MAC/Serial da ONU
* @param {string} onuType - Tipo da ONU (para determinar número de portas)
* @returns {Promise} - Promise com resultado
*/
async configurarIPoEFiberhome(serial, onuType = 'AN5506-02-B') {
try {
const VLAN_IPOE = 977;
this.logger.info('Iniciando configuração IPoE FiberHome via TL1', { serial, vlan: VLAN_IPOE });
const conectado = await this.conectarUNM2000();
if (!conectado) {
throw new Error('Não foi possível conectar ao UNM2000');
}
// Buscar ONU registrada pelo serial (retorna o objeto diretamente ou lança exceção)
const onuInfo = await this.buscarOnuRegistrada(serial);
const nameOlt = onuInfo.nameOlt || this.config.olt.name;
const portAlias = onuInfo.portAlias;
this.logger.info('ONU encontrada, reconfigurando WAN Service', { nameOlt, portAlias, serial, vlan: VLAN_IPOE });
// SET-WANSERVICE com VLAN 977
const numPortas = onuType === 'AN5506-02-B' ? 2 : 1;
for (let porta = 1; porta <= numPortas; porta++) {
const setWanCmd = `SET-WANSERVICE::OLTID=${nameOlt},PONID=NA-NA-${portAlias},ONUIDTYPE=MAC,ONUID=${serial}:${this.commandId++}::STATUS=1,MODE=2,CONNTYPE=1,VLAN=${VLAN_IPOE},COS=0,QOS=2,UPORT=${porta};`;
this.logger.debug(`Configurando WAN Service IPoE porta ${porta}`, { comando: setWanCmd });
const resultado = await this.executarComandoTL1(setWanCmd);
if (!resultado.success) {
this.logger.warn(`Aviso ao configurar WAN porta ${porta}: ${resultado.error}`);
}
await new Promise(resolve => setTimeout(resolve, 1000));
}
// Reiniciar ONU para aplicar
await new Promise(resolve => setTimeout(resolve, 2000));
const resetCmd = `RESET-ONU::OLTID=${nameOlt},PONID=NA-NA-${portAlias},ONUIDTYPE=MAC,ONUID=${serial}:${this.commandId++}::;`;
this.logger.debug('Reiniciando ONU após IPoE', { comando: resetCmd });
const resultadoReset = await this.executarComandoTL1(resetCmd);
if (!resultadoReset.success) {
this.logger.warn(`Aviso ao reiniciar ONU: ${resultadoReset.error}`);
}
this.logger.info('IPoE FiberHome configurado com sucesso', { serial, vlan: VLAN_IPOE });
return {
success: true,
message: `VLAN alterada para ${VLAN_IPOE} (IPoE)`,
details: {
olt: nameOlt,
porta: portAlias,
serial,
vlan: VLAN_IPOE,
portas: numPortas
}
};
} catch (error) {
this.logger.error('Erro ao configurar IPoE FiberHome', { serial, error: error.message });
return {
success: false,
error: error.message
};
}
}
} }
module.exports = FiberhomeManager; module.exports = FiberhomeManager;
+190
View File
@@ -1832,6 +1832,196 @@ class SSHManager {
}; };
} }
} }
/**
* Configura IPoE em ONU Datacom: altera VLAN da ethernet e service-ports para 977
* 1. Busca service-ports existentes
* 2. Busca a ONU (slot/onuId) pelo serial
* 3. Remove service-ports antigos
* 4. Altera ethernet native vlan para 977
* 5. Cria novos service-ports com VLAN 977
* 6. Commit
* @param {string} equipmentId - ID do equipamento OLT (ex: olt_dito)
* @param {string} slot - Slot da ONU (ex: 1/1/1)
* @param {string} onuId - ID da ONU (ex: 5)
* @returns {Promise} - Promise com resultado da operação
*/
async configIPoEDatacom(equipmentId, slot, onuId) {
console.log(`🔗 [IPoE Datacom] Iniciando - OLT: ${equipmentId}, Slot: ${slot}, ONU: ${onuId}`);
return new Promise(async (resolve, reject) => {
try {
const connection = await this.connect(equipmentId);
if (!connection.success) {
throw new Error(`Falha na conexão: ${connection.message}`);
}
// Buscar service-ports existentes
const spCommand = `show running-config service-port | context-match "gpon ${slot} onu ${onuId}"`;
const spResult = await this.executeCommand(connection.connectionId, spCommand);
const servicePorts = spResult.success ? this.parseServicePorts(spResult.output) : [];
if (servicePorts.length === 0) {
this.disconnect(connection.connectionId);
return resolve({
success: false,
message: `Nenhum service-port encontrado para ONU ${onuId} no slot ${slot}`
});
}
console.log(`🔌 [IPoE Datacom] Service-ports encontrados: ${servicePorts.join(', ')}`);
const conn = this.connections.get(connection.connectionId);
const VLAN_IPOE = 977;
conn.connection.shell((err, stream) => {
if (err) {
this.disconnect(connection.connectionId);
reject(new Error(`Erro ao abrir shell: ${err.message}`));
return;
}
let output = '';
let step = 0;
let isComplete = false;
let newServicePortId = null;
// Sequência de comandos:
// 0: config
// 1..N: no service-port X (remover antigos)
// N+1: interface gpon {slot}
// N+2: onu {onuId}
// N+3: ethernet 1
// N+4: native vlan vlan-id 977
// N+5: top
// N+6: service-port new
// N+7: gpon {slot} onu {onuId} gem 1 match vlan vlan-id 977 action vlan replace vlan-id 977
// N+8: commit
// N+9: top
// N+10: exit
// N+11: exit
const commands = [
'config',
...servicePorts.map(sp => `no service-port ${sp}`),
`interface gpon ${slot}`,
`onu ${onuId}`,
'ethernet 1',
`native vlan vlan-id ${VLAN_IPOE}`,
'top',
'service-port new',
`gpon ${slot} onu ${onuId} gem 1 match vlan vlan-id ${VLAN_IPOE} action vlan replace vlan-id ${VLAN_IPOE}`,
'commit',
'top',
'exit',
'exit'
];
const removeCount = servicePorts.length;
const ifaceIdx = 1 + removeCount; // interface gpon
const onuIdx = ifaceIdx + 1; // onu
const ethIdx = onuIdx + 1; // ethernet 1
const vlanIdx = ethIdx + 1; // native vlan
const topAfterVlanIdx = vlanIdx + 1; // top (back to config)
const spNewIdx = topAfterVlanIdx + 1; // service-port new
const spCfgIdx = spNewIdx + 1; // gpon ... match vlan
const commitIdx = spCfgIdx + 1; // commit
const topAfterCommitIdx = commitIdx + 1; // top
const exit1Idx = topAfterCommitIdx + 1; // exit
const exit2Idx = exit1Idx + 1; // exit
stream.on('data', (data) => {
const dataStr = data.toString();
output += dataStr;
console.log(`📨 [IPoE] Recebido: ${dataStr.trim()}`);
// Capturar novo service-port ID
if (dataStr.includes('(config-service-port-')) {
const match = dataStr.match(/\(config-service-port-(\d+)\)/);
if (match && !newServicePortId) {
newServicePortId = match[1];
console.log(`✅ [IPoE] Novo service-port ID: ${newServicePortId}`);
}
}
if (step < commands.length) {
let shouldSend = false;
if (step === 0 && dataStr.includes('#')) {
shouldSend = true; // prompt inicial → config
} else if (step >= 1 && step <= removeCount && dataStr.includes('(config)#')) {
shouldSend = true; // modo config → no service-port X
} else if (step === ifaceIdx && dataStr.includes('(config)#')) {
shouldSend = true; // modo config → interface gpon
} else if (step === onuIdx && dataStr.includes('(config-gpon')) {
shouldSend = true; // modo gpon → onu
} else if (step === ethIdx && dataStr.includes('(config-gpon-onu')) {
shouldSend = true; // modo onu → ethernet 1
} else if (step === vlanIdx && dataStr.includes('(config-ethernet')) {
shouldSend = true; // modo ethernet → native vlan
} else if (step === topAfterVlanIdx && dataStr.includes('(config-ethernet')) {
shouldSend = true; // após vlan → top
} else if (step === spNewIdx && dataStr.includes('(config)#')) {
shouldSend = true; // config → service-port new
} else if (step === spCfgIdx && dataStr.includes('(config-service-port')) {
shouldSend = true; // service-port → gpon ... match vlan
} else if (step === commitIdx && dataStr.includes('(config-service-port')) {
shouldSend = true; // service-port → commit
} else if (step === topAfterCommitIdx && dataStr.includes('(config-service-port')) {
shouldSend = true; // service-port → top
} else if (step === exit1Idx && dataStr.includes('(config)#')) {
shouldSend = true; // config → exit
} else if (step === exit2Idx && dataStr.includes('#') && !dataStr.includes('(config')) {
shouldSend = true; // prompt → exit
}
if (shouldSend) {
console.log(`📝 [IPoE] Comando ${step + 1}/${commands.length}: ${commands[step]}`);
stream.write(commands[step] + '\n');
step++;
}
} else if (!isComplete && dataStr.includes('#') && !dataStr.includes('(config')) {
isComplete = true;
setTimeout(() => { stream.end(); }, 1000);
}
});
stream.on('close', () => {
this.disconnect(connection.connectionId);
console.log(`✅ [IPoE Datacom] Concluído - ONU ${onuId} no slot ${slot}`);
resolve({
success: true,
message: `VLAN alterada para ${VLAN_IPOE} (IPoE)`,
output: output.trim(),
slot,
onuId,
vlanId: VLAN_IPOE,
oldServicePorts: servicePorts,
newServicePortId
});
});
stream.on('error', (err) => {
this.disconnect(connection.connectionId);
reject(new Error(`Erro no shell: ${err.message}`));
});
setTimeout(() => {
if (!stream.destroyed && !isComplete) {
console.log(`⏰ [IPoE Datacom] Timeout`);
stream.end();
this.disconnect(connection.connectionId);
reject(new Error('Timeout na operação IPoE'));
}
}, 90000);
});
} catch (error) {
console.error(`❌ [IPoE Datacom] Erro:`, error);
reject(new Error(`Erro IPoE Datacom: ${error.message}`));
}
});
}
} }
module.exports = SSHManager; module.exports = SSHManager;
+3 -20
View File
@@ -916,26 +916,9 @@ class TopSappAPI {
} }
} }
/** // Nota: AlterarServico não suporta campos DHCP (dhcp_username, dhcp_agent_circuit_id, dhcp_liberar).
* Configurar serviço para IPoE (DHCP Option 82) // Esses campos só existem no CadastrarClienteServico (criação de serviço novo).
* Define dhcp_username, dhcp_agent_circuit_id e dhcp_liberar no serviço // A configuração IPoE é gerada pelo bot e deve ser aplicada manualmente no painel TopSapp.
*/
async configurarIPoE(idCliente, idServico, dhcpAgentCircuitId, location = '', credentials) {
const instance = this.getInstanceByLocation(location);
try {
const session = await this.getValidSession(instance, credentials);
return await this.makeRequest('AlterarServico', {
idUsuario: session.idUsuario || 1,
idCliente: parseInt(idCliente),
idServico: parseInt(idServico),
dhcp_username: dhcpAgentCircuitId,
dhcp_agent_circuit_id: dhcpAgentCircuitId,
dhcp_liberar: '1'
}, instance, credentials);
} catch (error) {
return { success: false, error: error.message };
}
}
/** /**
* Listar todas as instâncias disponíveis * Listar todas as instâncias disponíveis
+13 -15
View File
@@ -1309,23 +1309,21 @@ class TopSappManager {
} }
const circuitId = `${prefixo}:${serial}`; const circuitId = `${prefixo}:${serial}`;
const login = servico.usuario || servico.pppoe_login || servico.login || '';
logger.info(`[IPoE] Configurando serviço ${idServico} do cliente ${idCliente}: circuit_id=${circuitId}`); logger.info(`[IPoE] Dados gerados para serviço ${idServico} do cliente ${idCliente}: circuit_id=${circuitId}`);
const resultado = await this.api.configurarIPoE(idCliente, idServico, circuitId, location, credentials); // A API AlterarServico não suporta campos DHCP.
// Retornamos os dados calculados para configuração manual no painel TopSapp.
if (resultado.success) { return {
return { success: true,
success: true, circuitId,
circuitId, prefixo,
prefixo, serial,
serial, baseInfo,
baseInfo, login,
servico: servico.descricao || servico.nome || 'N/A' servico: servico.descricao || servico.nome || 'N/A'
}; };
}
return resultado;
} catch (error) { } catch (error) {
return { success: false, error: error.message }; return { success: false, error: error.message };
} }