Ferramentas/RCVinculaPartesLivroAntigo/database/firebird.py
2025-12-02 10:37:13 -03:00

76 lines
2.6 KiB
Python

from typing import Optional
from sqlalchemy import create_engine, text
from sqlalchemy.engine import Engine
from sqlalchemy.exc import DBAPIError, OperationalError
from firebird.driver.types import DatabaseError as FbDatabaseError
from actions.config.config_ini import ConfigIni
from actions.firebird.parse_firebird_path import ParseFirebirdPath
from actions.hexCipher.hex_chipher import HexCipher
from actions.ui.ui import db_fail
class Firebird:
_engine: Optional[Engine] = None
hex_cipher: Optional[HexCipher] = None
@classmethod
def get_engine(cls) -> Engine:
# Cria a instância de descriptografia apenas uma vez
if cls.hex_cipher is None:
cls.hex_cipher = HexCipher(key="Wallace&Gromitt")
# Lê o arquivo INI com os parâmetros
database = ConfigIni.read("Config.ini")
# ----------------------------------------------------------------------
# Descriptografa o valor bruto do BaseDados ANTES do parser.
# Ex: "127.0.0.1/3050:S:\Bases\SANTARITA.FDB"
# ----------------------------------------------------------------------
base_raw = cls.hex_cipher.decrypt(database["Geral"]["BaseDados"])
# Parser converte "host/port:path" → dict {host, port, path}
base_info = ParseFirebirdPath.execute(base_raw)
# Descriptografa usuário e senha
user = cls.hex_cipher.decrypt(database["Geral"]["Usuario"])
passwd = cls.hex_cipher.decrypt(database["Geral"]["Senha"])
# Charset da conexão
charset = "ISO8859_1"
# Monta o DSN final no padrão aceito pelo firebird-driver
dsn = (
f"firebird+firebird://{user}:{passwd}"
f"@{base_info['host']}:{base_info['port']}/{base_info['path']}"
)
# Cria a engine apenas uma vez (singleton)
if cls._engine is None:
try:
cls._engine = create_engine(
dsn,
connect_args={"charset": charset},
pool_pre_ping=True,
pool_size=5,
max_overflow=10,
)
# Testa a conexão imediatamente para evitar erros silenciosos
with cls._engine.connect() as conn:
conn.execute(text("SELECT 1 FROM RDB$DATABASE"))
except (OperationalError, DBAPIError, FbDatabaseError) as e:
db_fail("Erro ao conectar ao Firebird:")
db_fail(str(e))
raise
return cls._engine
@classmethod
def dispose(cls):
if cls._engine:
cls._engine.dispose()
cls._engine = None