viabiliza/controller/viabilidadeController.js
Rafael Lopes 827855295e FEAT: Novos tipos de arquivos são permitidos
- Excel, CSV(; , ou tabulação) e TXT são agora aceitos para upload.
- Formato de dados atualizado para arquivos que fogem do padrão pré definido.
2026-05-04 16:38:37 -03:00

176 lines
6.3 KiB
JavaScript

const { consultarViabilidade, discoverDataType } = require('../service/viabilidadeService');
const { processCsvFile, countValidLines } = require('../service/csvService');
const { getJob, createJob } = require('../service/jobStore.service');
const fs = require('fs');
const path = require('path');
// Controlador para consultar viabilidade
async function consultarViabilidadeController(req, res) {
try {
const data = req.body;
data.source = 'viabiliza.sothis.com.br';
const result = await consultarViabilidade(data);
res.json(result);
} catch (error) {
console.error("Erro ao consultar viabilidade:", error && (error.message || error));
res.status(500).json({ error: "Erro ao consultar viabilidade" });
}
}
// Controlador para consultar viabilidade via geolocalização
async function consultarViaGeolocalizacaoController(req, res) {
try {
const data = req.body;
data.source = 'viabiliza.sothis.com.br';
const result = await consultarViabilidade(data);
res.json(result);
} catch (error) {
console.error("Erro ao consultar viabilidade por geolocalização:", error && (error.message || error));
res.status(500).json({ error: "Erro ao consultar viabilidade por geolocalização" });
}
}
async function uploadCsvFile(req, res) {
try {
// validação simples: verifica se multer populou req.file
if (!req.file) {
return res.status(400).json({ error: 'Nenhum arquivo enviado. Campo do form deve ser "csvfile".' });
}
const filePath = req.file.path;
const originalName = req.file.originalname || req.file.filename || 'input.csv';
// Verifica o tipo de dados do CSV
const dataType = await discoverDataType(filePath);
if (dataType === 'unknown') {
return res.status(400).json({ error: 'Formato invalido. Envie CSV, XLS ou XLSX com CEP+Numero, CEP+Endereco, ou Latitude+Longitude.' });
}
// Conta as linhas válidas primeiro
const total = await countValidLines(filePath);
if (total === 0) {
return res.status(400).json({ error: 'Nenhuma linha valida encontrada. Verifique se ha CEP+Numero, CEP+Endereco, ou Latitude+Longitude.' });
}
// Cria o job
const jobId = createJob(total);
// Inicia o processamento em background (não aguarda)
processCsvFile(jobId, filePath, originalName).catch(err => {
console.error('Erro no processamento em background:', err);
// Em caso de erro, marca o job como falhado
require('../service/jobStore.service').failJob(jobId, err.message);
});
// Retorna o jobId imediatamente para acompanhamento em tempo real
return res.json({ jobId });
} catch (error) {
console.error("Erro ao iniciar processamento do CSV:", error && (error.message || error));
return res.status(500).json({ error: 'Erro ao iniciar processamento do CSV' });
}
}
async function getJobController(req, res) {
try {
const jobId = req.params.jobId;
const job = getJob(jobId);
if (!job) {
return res.status(404).json({ error: 'Job não encontrado' });
}
res.json(job);
} catch (error) {
console.error("Erro ao obter job:", error && (error.message || error));
return res.status(500).json({ error: 'Erro ao obter job' });
}
}
// Controlador para download do CSV processado
// Verifica se o job está concluído e serve o arquivo para download
async function downloadCsvController(req, res) {
try {
const jobId = req.params.jobId;
const job = getJob(jobId);
// Verifica se o job existe, está concluído e tem um link de download
if (!job) {
return res.status(404).json({ error: 'Job não encontrado' });
}
if (job.status !== 'done') {
return res.status(400).json({ error: 'Processamento ainda não concluído' });
}
if (!job.download) {
return res.status(404).json({ error: 'Arquivo de download não disponível' });
}
// Extrai o nome do arquivo do campo download (ex: '/download/processed_123.csv' -> 'processed_123.csv')
const filename = path.basename(job.download);
const filePath = path.join(__dirname, '..', 'outputs', filename);
// Verifica se o arquivo existe no sistema de arquivos
if (!fs.existsSync(filePath)) {
return res.status(404).json({ error: 'Arquivo não encontrado no servidor' });
}
// Inicia o download do arquivo
res.download(filePath, filename, (err) => {
if (err) {
console.error("Erro ao fazer download do arquivo:", err);
// Se o download falhar, envia erro (mas headers já podem ter sido enviados)
if (!res.headersSent) {
res.status(500).json({ error: 'Erro ao fazer download do arquivo' });
}
}
});
} catch (error) {
console.error("Erro no controlador de download:", error && (error.message || error));
if (!res.headersSent) {
res.status(500).json({ error: 'Erro interno no servidor' });
}
}
}
// Controlador para download dos modelos de CSV
// Aceita parâmetro :type ('cep' ou 'geo') para escolher qual modelo baixar
async function downloadModelController(req, res) {
try {
const type = req.params.type;
let filename;
// Define o nome do arquivo baseado no tipo
if (type === 'cep') {
filename = 'modelo.viabilidade-cep.csv';
} else if (type === 'geo') {
filename = 'modelo.viabilidade-geolocalizacao.csv';
} else {
return res.status(400).json({ error: 'Tipo de modelo inválido. Use "cep" ou "geo".' });
}
const filePath = path.join(__dirname, '..', 'models', filename);
// Verifica se o arquivo existe
if (!fs.existsSync(filePath)) {
return res.status(404).json({ error: 'Arquivo de modelo não encontrado' });
}
// Inicia o download do arquivo
res.download(filePath, filename, (err) => {
if (err) {
console.error("Erro ao fazer download do modelo:", err);
if (!res.headersSent) {
res.status(500).json({ error: 'Erro ao fazer download do modelo' });
}
}
});
} catch (error) {
console.error("Erro no controlador de download de modelo:", error && (error.message || error));
if (!res.headersSent) {
res.status(500).json({ error: 'Erro interno no servidor' });
}
}
}
module.exports = { consultarViabilidadeController, uploadCsvFile, getJobController, downloadCsvController, downloadModelController, consultarViaGeolocalizacaoController };