package com.seconectai.condocontab; import com.seconectai.condocontab.auth.ApiKeyService; import com.seconectai.condocontab.auth.JwtService; import com.seconectai.condocontab.auth.http.AuthHandlers; import com.seconectai.condocontab.auth.http.AuthMiddleware; import com.seconectai.condocontab.config.AppConfig; import com.seconectai.condocontab.config.DataSourceProvider; import com.seconectai.condocontab.db.MigrationRunner; import com.seconectai.condocontab.financeiro.AbacatePayClient; import com.seconectai.condocontab.financeiro.AbacatePayWebhookHandler; import com.seconectai.condocontab.financeiro.BloqueioJob; import com.seconectai.condocontab.financeiro.FinanceiroHandlers; import com.seconectai.condocontab.http.HttpResponses; import com.seconectai.condocontab.http.Router; import com.seconectai.condocontab.http.StaticFileHandler; import com.seconectai.condocontab.integracao.EmailClient; import com.seconectai.condocontab.integracao.EvolutionApiClient; import com.seconectai.condocontab.integracao.ExternalBridgeHandler; import com.seconectai.condocontab.master.http.MasterHandlers; import com.seconectai.condocontab.tenant.TenantDataSourceProvider; import com.seconectai.condocontab.tenant.http.ClienteHandlers; import com.seconectai.condocontab.tenant.provisioning.TenantProvisioner; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpServer; import java.net.InetSocketAddress; import java.nio.file.Path; import java.sql.Connection; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public final class Main { private Main() { } public static void main(String[] args) { try { AppConfig config = AppConfig.fromEnv(); DataSourceProvider dataSourceProvider = new DataSourceProvider(config); dataSourceProvider.aguardarConexaoMaster(30, 1000); try (Connection conn = dataSourceProvider.getMasterConnection()) { MigrationRunner.runMigrations(conn, "migrations/master"); } JwtService jwtService = new JwtService(config.jwtSecret()); ApiKeyService apiKeyService = new ApiKeyService(dataSourceProvider); AbacatePayClient abacatePayClient = new AbacatePayClient(config, dataSourceProvider); EvolutionApiClient evolutionApiClient = new EvolutionApiClient(config); EmailClient emailClient = new EmailClient(); AuthHandlers authHandlers = new AuthHandlers(config, dataSourceProvider, jwtService); AuthMiddleware authMiddleware = new AuthMiddleware(jwtService, apiKeyService); TenantDataSourceProvider tenantDataSourceProvider = new TenantDataSourceProvider(config, dataSourceProvider); MasterHandlers masterHandlers = new MasterHandlers(dataSourceProvider, new TenantProvisioner(config), evolutionApiClient, config.jwtSecret()); ClienteHandlers clienteHandlers = new ClienteHandlers(tenantDataSourceProvider, dataSourceProvider, Path.of("/app/uploads"), evolutionApiClient, emailClient); FinanceiroHandlers financeiroHandlers = new FinanceiroHandlers(dataSourceProvider, abacatePayClient); AbacatePayWebhookHandler abacatePayWebhookHandler = new AbacatePayWebhookHandler(dataSourceProvider, abacatePayClient); ExternalBridgeHandler externalBridgeHandler = new ExternalBridgeHandler(tenantDataSourceProvider, dataSourceProvider, evolutionApiClient); if ("worker".equalsIgnoreCase(System.getenv().getOrDefault("APP_MODE", "web"))) { Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> { try { int processados = clienteHandlers.processarFilaEnvios(); if (processados > 0) System.out.println("Mensageiro processou " + processados + " mensagens"); } catch (Exception e) { e.printStackTrace(System.err); } }, 2, 5, TimeUnit.SECONDS); System.out.println("Mensageiro de envios iniciado"); new CountDownLatch(1).await(); return; } Router router = new Router(); router.get("/health", Main::health); router.post("/api/master/login", authHandlers.masterLogin()); router.post("/api/auth/login", authHandlers.funcionarioLogin()); router.post("/api/master/webhooks/abacatepay", abacatePayWebhookHandler); router.post("/api/webhooks/evolution/respostas", externalBridgeHandler); router.prefix("/api/webhooks/evolution/respostas/", externalBridgeHandler); router.post("/api/integracao/mensagens", authMiddleware.exigirApiKey(externalBridgeHandler)); router.get("/api/integracao/respostas", authMiddleware.exigirApiKey(externalBridgeHandler)); router.get("/api/integracao/evolution-instancia", authMiddleware.exigirApiKey(externalBridgeHandler)); router.prefix("/api/master/", authMiddleware.exigirMaster(masterHandlers)); router.prefix("/api/financeiro/", authMiddleware.exigirFuncionario(financeiroHandlers)); router.prefix("/api/", authMiddleware.exigirFuncionario(clienteHandlers)); router.fallback(new StaticFileHandler()); HttpServer server = HttpServer.create(new InetSocketAddress(config.httpPort()), 0); server.createContext("/", router); server.setExecutor(Executors.newVirtualThreadPerTaskExecutor()); server.start(); Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new BloqueioJob(dataSourceProvider), 1, 24 * 60 * 60, TimeUnit.SECONDS); System.out.println("Servidor HTTP iniciado na porta " + config.httpPort()); } catch (Exception e) { System.err.println("Falha ao iniciar aplicacao: " + e.getMessage()); e.printStackTrace(System.err); System.exit(1); } } private static void health(HttpExchange exchange) throws java.io.IOException { if (!"GET".equals(exchange.getRequestMethod())) { exchange.sendResponseHeaders(405, -1); return; } HttpResponses.json(exchange, 200, Map.of("status", "ok")); } private static void apiNaoImplementada(HttpExchange exchange) throws java.io.IOException { HttpResponses.json(exchange, 404, Map.of("erro", "endpoint_nao_implementado")); } }