fix: implement proper database connection context manager

- Created DBConnection class to manage database connections
- Each connection is now properly created and closed
- Removed global connection pool to fix thread issues
This commit is contained in:
Josh Finlay 2025-01-08 08:48:38 +10:00
parent a0533e1d78
commit a3ecf3a606
1 changed files with 24 additions and 14 deletions

View File

@ -105,17 +105,27 @@ ha_mqtt = HomeAssistantMQTT()
DB_PATH = "gatekeeper.db" # Database file path
# Database connection handling
async def get_db():
class DBConnection:
def __init__(self):
self.db = None
async def __aenter__(self):
self.db = await aiosqlite.connect(DB_PATH)
self.db.row_factory = aiosqlite.Row
return self.db
async def __aexit__(self, exc_type, exc_val, exc_tb):
await self.db.close()
def get_db():
"""Get a new database connection"""
db = await aiosqlite.connect(DB_PATH)
db.row_factory = aiosqlite.Row
return db
return DBConnection()
# Set up MQTT event logging
async def log_mqtt_event(action: str, success: bool = True):
"""Log MQTT events to the database and log file"""
logger.info(f"MQTT Event - {action} (Success: {success})")
async with await get_db() as db:
async with get_db() as db:
await db.execute(
"INSERT INTO events (timestamp, action, source, success) VALUES (?, ?, ?, ?)",
(datetime.utcnow().isoformat(), action, "MQTT", success)
@ -188,7 +198,7 @@ async def update_gate_status():
logger.info(f"Gate status changed to: {'open' if current_status else 'closed'}")
logger.debug("Updating database with new status")
async with await get_db() as db:
async with get_db() as db:
await db.execute(
"INSERT INTO gate_status (timestamp) VALUES (?)",
(timestamp.isoformat(),)
@ -258,7 +268,7 @@ async def check_auto_close():
logger.warning(f"Gate has been open for {time_open:.1f} seconds, auto-closing")
timestamp = current_time.isoformat()
async with await get_db() as db:
async with get_db() as db:
await db.execute(
"INSERT INTO events (timestamp, action, source, success) VALUES (?, ?, ?, ?)",
(timestamp, "auto-close", "system", True)
@ -314,7 +324,7 @@ async def trigger():
current_status = GPIO.input(settings.gpio.statusPin) == GPIO.HIGH
# Log event
async with await get_db() as db:
async with get_db() as db:
await db.execute(
"INSERT INTO events (timestamp, action, source, success) VALUES (?, ?, ?, ?)",
(timestamp, "trigger gate", "api", success)
@ -333,7 +343,7 @@ async def get_status():
settings = app.state.current_settings or Settings()
is_open = GPIO.input(settings.gpio.statusPin) == GPIO.HIGH
async with await get_db() as db:
async with get_db() as db:
cursor = await db.execute(
"SELECT timestamp FROM gate_status ORDER BY timestamp DESC LIMIT 1"
)
@ -348,7 +358,7 @@ async def get_status():
@app.get("/api/events")
async def get_events(limit: int = 10, offset: int = 0):
"""Get recent gate events with pagination"""
async with await get_db() as db:
async with get_db() as db:
db.row_factory = aiosqlite.Row
# Get total count
@ -375,7 +385,7 @@ async def get_events(limit: int = 10, offset: int = 0):
@app.get("/api/settings")
async def get_settings():
"""Get current settings"""
async with await get_db() as db:
async with get_db() as db:
cursor = await db.execute("SELECT key, value FROM settings")
rows = await cursor.fetchall()
settings = {}
@ -408,7 +418,7 @@ async def get_settings():
async def update_settings(settings: Settings):
"""Update settings"""
try:
async with await get_db() as db:
async with get_db() as db:
# Update each setting
for key, value in settings.dict().items():
await db.execute(
@ -458,7 +468,7 @@ async def update_settings(settings: Settings):
return {"success": True}
except Exception as e:
# Log failure event
async with await get_db() as db:
async with get_db() as db:
await db.execute(
"INSERT INTO events (timestamp, action, source, success) VALUES (?, ?, ?, ?)",
(
@ -503,7 +513,7 @@ def setup_gpio():
# Database functions
async def init_db():
"""Initialize the SQLite database"""
async with await get_db() as db:
async with get_db() as db:
# Create events table
await db.execute("""
CREATE TABLE IF NOT EXISTS events (