76 lines
2.6 KiB
Python
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
|