Navegação

    Fórum Técnico Insoft4

    • Login
    • Pesquisar
    • Categorias
    • Recente
    • Tags
    • Popular
    • Usuários
    • Grupos

    Documentação Técnica - Parte 2

    Documentações
    doc-tecnica doc-for-devs-and-sup
    1
    1
    3
    Carregando Mais Posts
    • Mais Antigo para Mais Recente
    • Mais Recente para Mais Antigo
    • Mais Votados
    Responder
    • Responder como tópico
    Entre para responder
    Este tópico foi deletado. Apenas usuários com privilégios de moderação de tópico podem vê-lo.
    • G
      Gilberto Júnior Equipamentos última edição por

      🔹 Fluxo 3: Atualização de Configurações

      Explicação simplificada (Suporte):

      O usuário altera as configurações (ex: intervalo de leitura para 500ms, prefixo "ID:"). Ao salvar, as mudanças são aplicadas imediatamente sem reiniciar o sistema.

      Explicação técnica (Dev):

      [Frontend] SettingsForm.onSubmit(data)
        │
        ├─► PUT /settings/reader (axios)
        │     │
        │     CardService.updateReaderSettings(payload)
        │       ├─ ReaderSettingsStore.update(payload) → normaliza → grava JSON em disco
        │       └─ DeviceManager.applyReaderSettings(updated)
        │             └─ DigiconDG710Reader.applySettings(settings)
        │                   ├─ pollingMs = settings.intervalMs
        │                   ├─ continuousRead = settings.continuousRead
        │                   └─ reinicia loop de polling (clearTimeout + scheduleNextPoll)
        │
        └─► window.readerApi.syncRuntimeSettings(updated)  [IPC]
              └─ ipcMain: "reader-runtime-settings:update-cache"
                    └─ runtimeSettingsCache = { ...cache, ...payload }
                          (usado pelo auto-paste: appendNewLine)
      

      🔹 Fluxo 4: Reconexão de Leitores

      Explicação simplificada (Suporte):

      Se o leitor parar de responder, o usuário pode clicar em "Reconectar leitores" no menu da bandeja. O sistema faz disconnect e connect novamente automaticamente.

      Explicação técnica (Dev):

      [Tray menu: "Reconectar leitores"]
        │  ou [Frontend: botão Reconectar]
        ▼
      performReconnectReaders()
        │
        ├─► GET /readers → lista todos os leitores
        │
        └─► Para cada reader (em paralelo):
              POST /readers/disconnect { key }
              POST /readers/connect    { key }
              POST /readers/start      { key }
      

      🔹 Fluxo 5: Manutenção Automática de Leitores

      Explicação simplificada (Suporte):

      A cada 1,5 segundos, o sistema verifica se o leitor está conectado e escutando. Se estiver desconectado, tenta reconectar sozinho.

      Explicação técnica (Dev):

      setInterval(service.maintainReaders, 1500ms)
        │
        └─► CardService.maintainReaders()
              Para cada readerKey:
                reader.getStatus()
                ├─ !connected → reader.connect()
                └─ connected + !listening → reader.startListening()
              Erros → logger.debug (não interrompem)
      

      ⚙️ 5. ROTINAS E MÉTODOS IMPORTANTES

      🔸 bootstrap() — server.ts

      Descrição simplificada:

      Inicializa toda a API: verifica instância única, cria componentes, monta rotas e inicia o servidor.

      Descrição técnica:

      • Localização: insoft-readers-api/src/server.ts
      • Fluxo: ensureSingleApiInstance() → instância de todos os serviços → monta Express → escuta na porta
      • Parâmetros: nenhum (usa variáveis de ambiente)
      • Retorno: Promise<void>
      • Possíveis saídas de emergência: process.exit(0) (duplicata), process.exit(1) (falha crítica)

      🔸 runPollingTick() — DigiconDG710Reader.ts

      Descrição simplificada:

      O loop que "pergunta" ao hardware a cada N milissegundos se há um cartão presente.

      Descrição técnica:

      • Localização: DigiconDG710Reader (método privado)
      • Usa setTimeout recursivo (não setInterval), garantindo que o próximo tick só ocorre após o atual terminar
      • Gerencia estado wasCardPresent para evitar eventos duplicados no modo não-contínuo
      • Em caso de erro: registra em lastError e continua o polling no próximo tick
      • Parada: stopListening() define pollingActive = false; o finally do tick detecta isso e não agenda o próximo

      🔸 readMifareCard() — DigiconFacade.ts

      Descrição simplificada:

      Lê os bytes do cartão físico e os converte para um número decimal (o "código do cartão").

      Descrição técnica:

      • Localização: DigiconFacade
      • Parâmetros: handle: number → identificador do canal conectado
      • Retorno: { cardId: string; rawHex: string } | null
      • Algoritmo: buffer de 4 bytes → leitura em ordem decrescente de índice (big-endian) → hex string → BigInt(0x${rawHex}).toString(10)
      • Exemplo: bytes [0x4E, 0x61, 0xBC, 0x00] → rawHex "00BC614E" → cardId "12345678"
      • Em mock mode: retorna número aleatório de 8 dígitos

      🔸 applyRuntimeSettingsToEvent() — CardService.ts

      Descrição simplificada:

      Adiciona o prefixo e o sufixo configurados ao código do cartão antes de distribuí-lo.

      Descrição técnica:

      • Localização: CardService (método privado)
      • Parâmetros: event: CardReadEvent
      • Retorno: novo CardReadEvent com cardId = prefix + originalCardId + suffix
      • Não modifica o evento original (imutabilidade via spread {...event})
      • Exemplo: prefixo "ID:", sufixo "", cardId "12345678" → "ID:12345678"

      🔸 ensureApiRunning() — ApiProcessManager.ts

      Descrição simplificada:

      Garante que a API está disponível antes de abrir a janela. Tenta todas as formas de iniciá-la.

      Descrição técnica:

      • Localização: insoft-readers-app/electron/main/services/ApiProcessManager.ts
      • Retorno: Promise<void>
      • Lança Error apenas se todas as tentativas falharem
      • Em dev: spawna npm run dev:once; em prod: executa o .exe da pasta resources

      🔸 handleCardRead() — main.ts

      Descrição simplificada:

      Decide o que fazer quando um cartão é lido: mostrar na UI ou colar no aplicativo ativo.

      Descrição técnica:

      • Localização: insoft-readers-app/electron/main/main.ts
      • Se janela em foco: mainWindow.webContents.send("card:read", event)
      • Se janela em background: pasteToExternalFocusedApp(cardId, appendNewLine)
      • Também envia app:notification quando em background (aparece como toast)

      🔸 pasteToExternalFocusedApp() — main.ts

      Descrição simplificada:

      Cola o código do cartão no campo de texto ativo usando a área de transferência do Windows.

      Descrição técnica:

      • Localização: insoft-readers-app/electron/main/main.ts
      • Usa clipboard.writeText(cardId) do Electron
      • Executa VBScript pré-criado em %TEMP% (criado na inicialização para evitar latência)
        • insoft_paste.vbs: SendKeys "^v" (Ctrl+V)
        • insoft_paste_nl.vbs: SendKeys "^v{ENTER}" (Ctrl+V + Enter)
      • wscript.exe //B suprime diálogos; latência ~50ms vs ~1.500ms do PowerShell
      • Apenas funciona em win32

      🔗 6. INTEGRAÇÕES EXTERNAS

      DLL Nativa — DG710Facade.dll

      Item Detalhe
      Tipo DLL C/C++ do fabricante Digicon
      Arquitetura x64 (requerida; x86 causa erro detectável no log)
      Localização Configurável via DIGICON_DLL_PATH; buscada em ~9 caminhos candidatos
      Integração koffi (FFI puro TypeScript, sem recompilar addons Node)
      Funções usadas registryStart/Stop/IsStarted/GetChannelList, channelConnect/Disconnect/IsConnected/GetSerialNumber, mifareIsCardPresent, mifareReadCardSerialNumber
      Fallback Mock mode automático se a DLL não for encontrada

      Pontos de atenção:

      • A DLL deve estar acessível no mesmo diretório do executável ou em caminho absoluto
      • O processo deve ser x64 para carregar a DLL x64
      • A DLL pode requerer drivers do fabricante instalados no Windows

      NSSM — Non-Sucking Service Manager

      Item Detalhe
      Tipo Ferramenta externa de linha de comando
      Uso Gerenciar a API como Serviço Windows
      Comandos sc query <name> (verificar), nssm start <name> (iniciar)
      Requisito nssm.exe deve estar no PATH do sistema

      VBScript / wscript.exe

      Item Detalhe
      Tipo Runtime nativo do Windows
      Uso Simular Ctrl+V no aplicativo ativo (auto-paste)
      Mecanismo SendKeys "^v" / SendKeys "^v{ENTER}"
      Limitação Funciona apenas em Windows; requer que o aplicativo de destino suporte Ctrl+V

      🚨 7. TRATAMENTO DE ERROS E EXCEÇÕES

      Estratégia Geral

      Camada Estratégia
      Backend API Middleware global de erros; ZodError → 400; erros Digicon conhecidos → 503; outros → 500
      DeviceManager Erros de inicialização/discover logados, não propagados (sistema continua)
      CardService.maintainReaders Erros de auto-reconexão logados como debug, sem interrupção
      DigiconFacade Mock mode ativado silenciosamente se DLL não carregar
      Electron main Erros de startup da API encerram o app via app.quit()
      ApiProcessManager Lança Error se health check final falhar; Electron encerra
      Frontend useReaders captura erros axios e os expõe via estado error
      SSE (Electron) scheduleCardEventsReconnect(1500ms) em caso de falha ou disconnect

      Logs Importantes

      O backend usa pino com logs estruturados JSON. Nível padrão: info.

      Mensagem de Log Significado
      "Reader backend started" API iniciada com sucesso na porta
      "API já está em execução. Encerrando instância duplicada." Segunda instância detectada, saiu normalmente
      "Porta em uso por outro processo." Porta 3791 ocupada por processo externo
      "Reader initialization failed; continuing backend startup" Leitor não inicializou (hardware ausente?)
      "Digicon native DLL not loaded. Running in mock mode." DLL não encontrada; simulando hardware
      "Failed to load Digicon native DLL" Detalhe do erro ao carregar DLL (inclui arquitetura)
      "Reader discovery failed" Leitor não detectado no discover
      "Failed to connect Digicon reader" Falha ao conectar; lastError contém detalhes
      "Error while reading Digicon card" Erro durante polling de leitura
      "Card read" Cartão lido com sucesso (inclui o evento completo)
      "Shutting down backend" Shutdown iniciado (SIGTERM/SIGINT)

      Variáveis de Ambiente para Diagnóstico

      Variável Padrão Uso
      LOG_LEVEL info Nível de log (debug, info, warn, error)
      BACKEND_PORT 3791 Porta do servidor HTTP da API
      BACKEND_BASE_URL http://127.0.0.1:3791 URL base da API
      APP_CONTROL_URL http://127.0.0.1:3792 URL do AppControlServer
      DIGICON_DLL_PATH DG710Facade.dll Caminho explícito da DLL nativa
      READER_SETTINGS_FILE reader-runtime-settings.json (cwd) Arquivo de settings
      API_SERVICE_NAME InsoftReadersApiService Nome do serviço Windows
      API_EXE_NAME insoft-reader-api.exe Nome do executável da API
      API_EXE_PATH — Caminho absoluto do executável (override)
      APP_EXECUTABLE_PATH — Caminho do .exe da interface (override)

      🧪 8. CENÁRIOS COMUNS DE SUPORTE

      🛑 Cenário 1: O cartão não está sendo lido

      Sintoma Aproxima o cartão e nada acontece
      Possíveis causas (a) Leitor desconectado; (b) API não está rodando; (c) Leitor em estado "stopped"; (d) DLL não encontrada (modo mock)
      Como investigar 1. Abrir a interface → Dashboard → verificar se "Active Readers" > 0; 2. Verificar se status é "Connected" e "Listening" na página Readers; 3. Verificar logs do backend por "mock mode" ou "Reader not found"
      Como resolver 1. Página Readers → selecionar leitor → clicar "Conectar" e depois "Iniciar leitura"; 2. Menu da bandeja → "Reconectar leitores"; 3. Se DLL: verificar se DG710Facade.dll está no diretório da API

      🛑 Cenário 2: O código do cartão está errado (com caracteres extras)

      Sintoma O cartão é lido mas o código aparece com prefixo/sufixo estranho (ex: "AAA12345678BBBB")
      Possíveis causas Configurações de prefixo/sufixo estão definidas
      Como investigar Abrir interface → Settings → verificar campos "Prefix" e "Suffix"
      Como resolver Settings → limpar campos Prefix e Suffix → salvar

      🛑 Cenário 3: O cartão está sendo lido mas não é colado no aplicativo

      Sintoma O toast de notificação aparece mas o texto não é inserido no campo
      Possíveis causas (a) Janela do Insoft Readers está em foco (comportamento esperado); (b) Aplicativo de destino não suporta Ctrl+V
      Como investigar 1. Verificar se a janela do Insoft Readers está na frente — se sim, o modo é exibição na UI, não auto-paste; 2. Testar colar manualmente no campo do aplicativo (Ctrl+V)
      Como resolver Minimizar ou mover a janela do Insoft Readers para segundo plano antes de aproximar o cartão

      🛑 Cenário 4: A interface abre mas mostra erro de conexão

      Sintoma Frontend exibe mensagem de erro ao carregar leitores
      Possíveis causas API não está rodando na porta 3791
      Como investigar Abrir navegador → acessar http://127.0.0.1:3791/health → se retornar {"status":"ok"}, API está OK
      Como resolver 1. Aguardar alguns segundos (API pode estar iniciando); 2. Menu da bandeja → Reconectar leitores; 3. Fechar e reabrir o aplicativo

      🛑 Cenário 5: Erro "Arquitetura incompatível" no log

      Sintoma Log contém "Arquitetura incompatível: a DLL é x86 (32-bit)"
      Possíveis causas DG710Facade.dll é versão 32-bit mas o processo é 64-bit
      Como investigar Verificar qual versão da DLL está instalada
      Como resolver Substituir a DLL pela versão x64 fornecida pelo fabricante Digicon

      🛑 Cenário 6: Porta 3791 já está em uso

      Sintoma Log contém "Porta em uso por outro processo. Abortando inicialização da API." e a API não inicia
      Possíveis causas Outro processo ocupou a porta 3791
      Como investigar Executar no terminal: netstat -ano | findstr 3791 para ver qual processo usa a porta
      Como resolver Encerrar o processo conflitante ou configurar BACKEND_PORT para outra porta

      🛑 Cenário 7: Leitor conecta mas para de responder após um tempo

      Sintoma Leituras param sem erro aparente; leitor aparece como conectado mas não lê
      Possíveis causas (a) Leitor fisicamente desconectado (USB); (b) Timeout de hardware
      Como investigar Dashboard → verificar se "Listening" mudou para "Stopped" ou se há lastError na página Readers
      Como resolver O timer de manutenção (1,5s) tenta reconexão automática. Se persistir: desconectar fisicamente e reconectar o USB; usar "Reconectar leitores"

      📝 9. BOAS PRÁTICAS E OBSERVAÇÕES

      Adicionando Suporte a Novo Modelo de Leitor

      Para adicionar um novo leitor (ex: fabricante X, modelo Y):

      1. Criar pasta: insoft-readers-api/src/devices/fabricante-x/
      2. Implementar a interface ICardReader em uma nova classe
      3. Registrar em server.ts:
        registry.register("fabricante-x-modelY", () => new FabricanteXReaderY());
        
      4. Se usar DLL nativa: criar uma Facade similar ao DigiconFacade.ts

      Pontos Sensíveis ao Modificar

      Área Cuidado
      normalizeSettings() Limites de intervalMs (50ms–10s) estão validados aqui e também no Zod do settings.routes. Alterar um sem o outro cria inconsistência
      readMifareCard() A ordem de bytes (little-endian → big-endian) é específica do hardware Digicon. Alterar sem hardware para testar pode causar IDs incorretos
      pasteToExternalFocusedApp() Os arquivos .vbs são criados uma vez na inicialização. Se tmpdir() não for gravável, o auto-paste falha silenciosamente
      ensureSingleApiInstance() Depende do endpoint /health retornar exatamente { "status": "ok" }. Mudanças no formato quebram a detecção de instância duplicada
      Porta 3792 (AppControlServer) É usada bidirecionalmente: Electron escuta notificações vindas da API. Conflitos de porta impedem notificações no tray
      recentReads.splice(50) O histórico é armazenado apenas em memória. Reiniciar a API limpa o histórico

      Configuração de Runtime em Produção

      O arquivo reader-runtime-settings.json é persistido no diretório de trabalho (cwd) da API. Em produção, isso é o diretório do executável. Ao atualizar a API, preserve esse arquivo para não perder configurações.

      Modo de Desenvolvimento

      Para rodar o projeto em modo desenvolvimento:

      # Na raiz do monorepo — inicia todos os serviços simultaneamente:
      npm run dev
      
      # Separado:
      npm run dev:frontend   # Vite na porta 5173
      npm run dev:electron   # Electron + TypeScript watch
      # A API é iniciada automaticamente pelo Electron via ApiProcessManager
      

      Compilação para Produção

      # Gera instalador NSIS para Windows x64:
      npm run dist
      
      # Resultado em:
      # insoft-readers-app/electron/release/
      #   Insoft-Readers-1.0.0-Setup-x64.exe
      

      O instalador empacota:

      • resources/api/insoft-reader-api.exe — API compilada com pkg
      • resources/frontend/ — Build estático do React
      • resources/ — Preload, assets

      Diagrama de Dependências dos Pacotes

      @insoft/backend (API)
        ├── express          ← servidor HTTP
        ├── koffi            ← FFI para DLL nativa
        ├── pino             ← logging
        ├── zod              ← validação
        └── dotenv           ← variáveis de ambiente
      
      @insoft/electron
        └── electron         ← framework desktop
      
      @insoft/frontend
        ├── react            ← UI
        ├── zustand          ← estado global
        ├── axios            ← cliente HTTP
        ├── react-hook-form  ← formulários
        ├── zod              ← validação de forms
        ├── flowbite-react   ← componentes UI
        └── tailwindcss      ← estilos
      

      Documentação gerada a partir do código-fonte do projeto. Para atualizações, reanalise os arquivos correspondentes após mudanças significativas na arquitetura e atualize essa documentação.

      1 Resposta Última resposta Responder Citar 0
      • Primeiro post
        Último post
      Powered by NodeBB | Contributors