Ola pessoal!
Como muitos já sabem, o ffi-napi foi descontinuado e muitos projetos que usam ACBrLib com Node.js precisam migrar para uma alternativa. Alguns membros da comunidade sugeriram a biblioteca koffi
Fizemos alguns testes e funcionou como esperado.
Este tópico é um guia prático para quem precisa fazer essa migração. O koffi não só substitui o ffi-napi, como também elimina a necessidade do ref-napi!
Instalação
npm install koffi
Principais diferenças
Importação
// Antes (ffi-napi + ref-napi)
const ffi = require('ffi-napi');
const ref = require('ref-napi');
// Agora (apenas koffi)
const koffi = require('koffi');
Carregando a biblioteca
// Antes
const lib = ffi.Library(pathDll, { /* funções */ });
// Agora
const acbrcep = koffi.load(pathDll);
const lib = {
CEP_Inicializar: acbrcep.func('CEP_Inicializar', 'int', ['void **', 'string', 'string']),
CEP_Finalizar: acbrcep.func('CEP_Finalizar', 'int', ['void *']),
// outras funções...
};
Trabalhando com ponteiros
A inicialização de qualquer ACBrLib Multi-thread exige um parâmetro especial, o ponteiro (do tipo void **) handle.
O tratamento adequado do ponteiro handle evita falhas de segmentação (AV)!
Obs: os demais métodos recebem um ponteiro (void *)
Importante: Na ACBrLib Multi-Thread o mapeamento deve levar em consideração o ponteiro handle.
Leia mais sobre a ACBrLib Multi-Thread
// Antes (handle para inicialização)
let handle = ref.alloc('void *');
// Agora
let handle = koffi.alloc('void *', 1);
// Para usar o ponteiro nos demais métodos:
// Antes: handle.deref()
// Agora: koffi.decode(handle, 'void*')
Inteiros por referência
Alguns métodos da biblioteca exigem um buffer e uma variável do tipo inteiro (de leitura e escrita), como o exemplo CEP_UltimoRetorno. Ao executar o método, a biblioteca modificará esse inteiro.
Na maioria das linguagens, um inteiro (integer) é passado por valor (cópia), mas no nosso caso é por referência!
Para isso precisamos declarar esse integer especial.
// Antes
let tamanho = ref.alloc('int', 256);
// Agora (2 passos)
let tamanho = koffi.alloc('int', 1);
koffi.encode(tamanho, 'int', 256); // define o valor
Exemplo completo - Busca CEP
Código com koffi:
const koffi = require('koffi');
const path = require('path');
const TAMANHO_BUFFER = 1024;
const pathDllACBrLibCEP = path.join(__dirname, 'ACBrCEP64.dll');
const acbrcep = koffi.load(pathDllACBrLibCEP);
const lib = {
CEP_Inicializar: acbrcep.func('CEP_Inicializar', 'int', ['void **', 'string', 'string']),
CEP_Finalizar: acbrcep.func('CEP_Finalizar', 'int', ['void *']),
CEP_BuscarPorCEP: acbrcep.func('CEP_BuscarPorCEP', 'int', ['void *', 'string', 'char *', 'int *']),
CEP_ConfigGravar: acbrcep.func('CEP_ConfigGravar', 'int', ['void *', 'string']),
CEP_ConfigGravarValor: acbrcep.func('CEP_ConfigGravarValor', 'int', ['void *', 'string', 'string', 'string'])
};
// Inicialização
let handle = koffi.alloc('void *', 1);
let eArqConfig = path.resolve(__dirname, 'ACBrLib.ini');
let eChaveCrypt = '';
// Buffers
let aloc_sResposta = Buffer.alloc(TAMANHO_BUFFER);
let aloc_esTamanho = koffi.alloc('int', 1);
koffi.encode(aloc_esTamanho, 'int', TAMANHO_BUFFER);
// Execução
lib.CEP_Inicializar(handle, eArqConfig, eChaveCrypt);
// Configurações (opcional)
lib.CEP_ConfigGravarValor(koffi.decode(handle, 'void *'), 'CEP', 'WebService', '3');
// salvar configurações
lib.CEP_ConfigGravar(koffi.decode(handle, 'void *'), eArqConfig);
// Busca o CEP
lib.CEP_BuscarPorCEP(koffi.decode(handle, 'void *'), '18270-170', aloc_sResposta, aloc_esTamanho);
console.log('Resultado:', aloc_sResposta.toString());
// Finaliza
lib.CEP_Finalizar(koffi.decode(handle, 'void *'));
Links úteis
Documentação oficial do koffi
Mapeamento de funções
Trabalhando com ponteiros
Conclusão
A migração do ffi-napi para koffi é direta e o código resultante utiliza apenas uma dependência.
O exemplo acima demonstra o uso com ACBrLib CEP, mas a abordagem é aplicável a outras bibliotecas ACBr (NFe, SAT, etc.).
Testado com: ACBrLib CEP, mas deve funcionar com todas as outras libs (NFe, SAT, etc.)
_Espero que ajude! Se encontrarem algum problema ou tiverem sugestões, postem aqui. _