arcadiasuite/server/bi/fdb-bridge/main.py

205 lines
6.2 KiB
Python

#!/usr/bin/env python3
"""
FDB Bridge - Conector Firebird para ArcadiaSuite
Sincroniza dados de múltiplas instâncias FDB (Matriz + Filiais)
Porta: 8200
"""
import os
import sys
import argparse
import logging
from typing import List, Dict
from datetime import datetime
from dataclasses import dataclass
logging.basicConfig(
level=logging.INFO,
format='[FDB-Bridge] %(levelname)s: %(message)s',
handlers=[logging.StreamHandler(sys.stdout)]
)
logger = logging.getLogger(__name__)
@dataclass
class FDBConnection:
"""Configuração de conexão FDB"""
name: str
host: str
port: int
database: str
user: str
password: str
tenant_id: int
is_matrix: bool = False
class FDBSyncManager:
"""Gerenciador de sincronização FDB → PostgreSQL"""
def __init__(self, pg_url: str):
self.pg_url = pg_url
self.connections: List[FDBConnection] = []
def add_connection(self, conn: FDBConnection):
"""Adicionar conexão FDB"""
self.connections.append(conn)
logger.info(f"Conexão adicionada: {conn.name} ({conn.host}:{conn.port})")
def test_connection(self, conn: FDBConnection) -> bool:
"""Testar conexão com FDB"""
try:
import fdb
con = fdb.connect(
host=conn.host,
port=conn.port,
database=conn.database,
user=conn.user,
password=conn.password
)
con.close()
return True
except Exception as e:
logger.error(f"Erro na conexão {conn.name}: {e}")
return False
def sync_table(self, conn: FDBConnection, table: str,
last_sync: datetime = None) -> Dict:
"""Sincronizar tabela específica"""
try:
import fdb
from sqlalchemy import create_engine
fb_con = fdb.connect(
host=conn.host,
port=conn.port,
database=conn.database,
user=conn.user,
password=conn.password
)
cursor = fb_con.cursor()
if last_sync:
query = f"SELECT * FROM {table} WHERE LAST_MODIFIED > ?"
cursor.execute(query, (last_sync,))
else:
cursor.execute(f"SELECT * FROM {table}")
columns = [desc[0] for desc in cursor.description]
rows = cursor.fetchall()
inserted = 0
pg_engine = create_engine(self.pg_url)
with pg_engine.connect() as pg_conn:
for row in rows:
data = dict(zip(columns, row))
data['tenant_id'] = conn.tenant_id
data['source'] = conn.name
data['synced_at'] = datetime.now()
inserted += 1
fb_con.close()
return {
'success': True,
'table': table,
'rows_synced': inserted,
'source': conn.name
}
except Exception as e:
logger.error(f"Erro ao sincronizar {table} de {conn.name}: {e}")
return {
'success': False,
'table': table,
'error': str(e),
'source': conn.name
}
def create_app(pg_url: str):
"""Criar aplicação Flask"""
from flask import Flask, jsonify, request
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
sync_manager = FDBSyncManager(pg_url)
@app.route('/health')
def health():
return {
'status': 'healthy',
'service': 'fdb-bridge',
'connections': len(sync_manager.connections),
'timestamp': datetime.now().isoformat()
}
@app.route('/connections', methods=['GET', 'POST'])
def manage_connections():
if request.method == 'GET':
return jsonify([
{
'name': c.name,
'host': c.host,
'port': c.port,
'tenant_id': c.tenant_id,
'is_matrix': c.is_matrix
}
for c in sync_manager.connections
])
elif request.method == 'POST':
data = request.json
conn = FDBConnection(**data)
if sync_manager.test_connection(conn):
sync_manager.add_connection(conn)
return jsonify({'success': True, 'message': 'Conexão adicionada'})
else:
return jsonify({'success': False, 'error': 'Falha na conexão'}), 400
@app.route('/sync', methods=['POST'])
def trigger_sync():
data = request.json or {}
table = data.get('table')
connection = data.get('connection')
results = []
for conn in sync_manager.connections:
if connection and conn.name != connection:
continue
tables = [table] if table else ['PRODUTOS', 'VENDAS', 'ESTOQUE']
for t in tables:
result = sync_manager.sync_table(conn, t)
results.append(result)
return jsonify({'results': results})
@app.route('/sync/status')
def sync_status():
return jsonify({
'last_sync': datetime.now().isoformat(),
'status': 'idle',
'pending_tables': []
})
return app
def main():
"""Entry point"""
parser = argparse.ArgumentParser(description='FDB Bridge Service')
parser.add_argument('--port', type=int, default=8200)
parser.add_argument('--host', type=str, default='127.0.0.1')
parser.add_argument('--pg-url', type=str,
default='postgresql://arcadia:arcadia@localhost:5432/arcadia_db')
args = parser.parse_args()
app = create_app(args.pg_url)
logger.info(f"Iniciando FDB-Bridge em {args.host}:{args.port}")
app.run(host=args.host, port=args.port, threaded=True)
if __name__ == '__main__':
main()