Update main.py
This commit is contained in:
@@ -28,55 +28,71 @@ polling_task = None
|
|||||||
|
|
||||||
async def handle_button_click(callback_data: str, chat_id: int, message_id: int):
|
async def handle_button_click(callback_data: str, chat_id: int, message_id: int):
|
||||||
"""Handle inline button click"""
|
"""Handle inline button click"""
|
||||||
|
print(f"[BUTTON] Received callback: {callback_data} from chat {chat_id}")
|
||||||
|
|
||||||
if not callback_data.startswith("service_"):
|
if not callback_data.startswith("service_"):
|
||||||
|
print(f"[BUTTON] Invalid callback prefix: {callback_data}")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Parse: service_{action}_{id_or_name}
|
# Parse: service_{action}_{id_or_name}
|
||||||
parts = callback_data.split("_", 2)
|
parts = callback_data.split("_", 2)
|
||||||
if len(parts) != 3:
|
if len(parts) != 3:
|
||||||
|
print(f"[BUTTON] Invalid callback format: {callback_data} (got {len(parts)} parts)")
|
||||||
return
|
return
|
||||||
|
|
||||||
action = parts[1] # start, stop, restart
|
action = parts[1] # start, stop, restart
|
||||||
identifier = parts[2] # numeric service_id or 'name_{service_name}'
|
identifier = parts[2] # numeric service_id or 'name_{service_name}'
|
||||||
|
print(f"[BUTTON] Action: {action}, Identifier: {identifier}")
|
||||||
|
|
||||||
# Determine if identifier is service_id (numeric) or service_name (prefixed with 'name_')
|
# Determine if identifier is service_id (numeric) or service_name (prefixed with 'name_')
|
||||||
if identifier.startswith('name_'):
|
if identifier.startswith('name_'):
|
||||||
# Extract service name from identifier
|
# Extract service name from identifier
|
||||||
service_name = identifier[5:] # Remove 'name_' prefix
|
service_name = identifier[5:] # Remove 'name_' prefix
|
||||||
service_id = None
|
service_id = None
|
||||||
|
print(f"[BUTTON] Looking up service by name: {service_name}")
|
||||||
|
|
||||||
# Look up service_id from controller API
|
# Look up service_id from controller API
|
||||||
try:
|
try:
|
||||||
|
print(f"[BUTTON] Contacting controller at {CONTROLLER_API}/services")
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
headers = {"Authorization": f"Bearer {SECRET_TOKEN}"}
|
headers = {"Authorization": f"Bearer {SECRET_TOKEN}"}
|
||||||
async with session.get(f"{CONTROLLER_API}/services", headers=headers) as resp:
|
async with session.get(f"{CONTROLLER_API}/services", headers=headers) as resp:
|
||||||
|
print(f"[BUTTON] Controller response: HTTP {resp.status}")
|
||||||
if resp.status == 200:
|
if resp.status == 200:
|
||||||
services = await resp.json()
|
services = await resp.json()
|
||||||
|
print(f"[BUTTON] Found {len(services)} services: {[s.get('name') for s in services]}")
|
||||||
# Find service by name
|
# Find service by name
|
||||||
for svc in services:
|
for svc in services:
|
||||||
if svc.get('name') == service_name:
|
if svc.get('name') == service_name:
|
||||||
service_id = svc.get('id')
|
service_id = svc.get('id')
|
||||||
|
print(f"[BUTTON] Matched service '{service_name}' to ID {service_id}")
|
||||||
break
|
break
|
||||||
|
|
||||||
if not service_id:
|
if not service_id:
|
||||||
|
error_msg = f"❌ Service '{service_name}' not registered in controller"
|
||||||
|
print(f"[BUTTON] {error_msg}")
|
||||||
await bot.edit_message_text(
|
await bot.edit_message_text(
|
||||||
chat_id=chat_id,
|
chat_id=chat_id,
|
||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
text=f"❌ Service '{service_name}' not registered in controller"
|
text=error_msg
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
error_msg = f"❌ Failed to fetch services (HTTP {resp.status})"
|
||||||
|
print(f"[BUTTON] {error_msg}")
|
||||||
await bot.edit_message_text(
|
await bot.edit_message_text(
|
||||||
chat_id=chat_id,
|
chat_id=chat_id,
|
||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
text=f"❌ Failed to fetch services (HTTP {resp.status})"
|
text=error_msg
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
error_msg = f"❌ Error: {str(e)[:100]}"
|
||||||
|
print(f"[BUTTON] Exception during service lookup: {str(e)}")
|
||||||
await bot.edit_message_text(
|
await bot.edit_message_text(
|
||||||
chat_id=chat_id,
|
chat_id=chat_id,
|
||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
text=f"❌ Error: {str(e)[:100]}"
|
text=error_msg
|
||||||
)
|
)
|
||||||
await log_message(chat_id, f"Service lookup error", False, str(e))
|
await log_message(chat_id, f"Service lookup error", False, str(e))
|
||||||
return
|
return
|
||||||
@@ -84,32 +100,47 @@ async def handle_button_click(callback_data: str, chat_id: int, message_id: int)
|
|||||||
# Identifier is numeric service_id
|
# Identifier is numeric service_id
|
||||||
try:
|
try:
|
||||||
service_id = int(identifier)
|
service_id = int(identifier)
|
||||||
|
print(f"[BUTTON] Using numeric service_id: {service_id}")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
print(f"[BUTTON] Failed to parse service_id from: {identifier}")
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with aiohttp.ClientSession() as session:
|
|
||||||
api_url = f"{CONTROLLER_API}/services/{service_id}/action"
|
api_url = f"{CONTROLLER_API}/services/{service_id}/action"
|
||||||
|
print(f"[BUTTON] Executing {action} on service {service_id} at {api_url}")
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
headers = {"Authorization": f"Bearer {SECRET_TOKEN}"}
|
headers = {"Authorization": f"Bearer {SECRET_TOKEN}"}
|
||||||
data = {"action": action}
|
data = {"action": action}
|
||||||
|
print(f"[BUTTON] Sending POST request with data: {data}")
|
||||||
|
|
||||||
async with session.post(api_url, json=data, headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
async with session.post(api_url, json=data, headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
||||||
|
response_text = await resp.text()
|
||||||
|
print(f"[BUTTON] Controller response: HTTP {resp.status}")
|
||||||
|
print(f"[BUTTON] Response body: {response_text[:200]}")
|
||||||
|
|
||||||
if resp.status == 200:
|
if resp.status == 200:
|
||||||
|
success_msg = f"✅ Service action '{action}' executed successfully"
|
||||||
|
print(f"[BUTTON] Success: {success_msg}")
|
||||||
await bot.edit_message_text(
|
await bot.edit_message_text(
|
||||||
chat_id=chat_id,
|
chat_id=chat_id,
|
||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
text=f"✅ Service action '{action}' executed successfully"
|
text=success_msg
|
||||||
)
|
)
|
||||||
await log_message(chat_id, f"Action: {action} on service {service_id}", True)
|
await log_message(chat_id, f"Action: {action} on service {service_id}", True)
|
||||||
else:
|
else:
|
||||||
error_text = await resp.text()
|
error_msg = f"❌ Failed: {response_text[:100]}"
|
||||||
|
print(f"[BUTTON] Failed: {error_msg}")
|
||||||
await bot.edit_message_text(
|
await bot.edit_message_text(
|
||||||
chat_id=chat_id,
|
chat_id=chat_id,
|
||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
text=f"❌ Failed: {error_text[:100]}"
|
text=error_msg
|
||||||
)
|
)
|
||||||
await log_message(chat_id, f"Action failed: {action}", False, error_text)
|
await log_message(chat_id, f"Action failed: {action}", False, response_text)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
error_msg = f"❌ Exception: {str(e)[:100]}"
|
||||||
|
print(f"[BUTTON] Exception during action execution: {str(e)}")
|
||||||
|
print(f"[BUTTON] Full traceback:", exc_info=True)
|
||||||
await log_message(chat_id, f"Action error: {action}", False, str(e))
|
await log_message(chat_id, f"Action error: {action}", False, str(e))
|
||||||
|
|
||||||
async def poll_updates():
|
async def poll_updates():
|
||||||
@@ -117,27 +148,37 @@ async def poll_updates():
|
|||||||
global update_offset
|
global update_offset
|
||||||
|
|
||||||
if not bot:
|
if not bot:
|
||||||
|
print("[POLLING] Bot not configured, skipping polling")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
print("[POLLING] Starting update polling")
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
updates = await bot.get_updates(offset=update_offset, timeout=30)
|
updates = await bot.get_updates(offset=update_offset, timeout=30)
|
||||||
|
|
||||||
|
if updates:
|
||||||
|
print(f"[POLLING] Received {len(updates)} updates")
|
||||||
|
|
||||||
for update in updates:
|
for update in updates:
|
||||||
update_offset = update.update_id + 1
|
update_offset = update.update_id + 1
|
||||||
|
|
||||||
if update.callback_query:
|
if update.callback_query:
|
||||||
query = update.callback_query
|
query = update.callback_query
|
||||||
|
print(f"[POLLING] Processing callback query: {query.data}")
|
||||||
await handle_button_click(
|
await handle_button_click(
|
||||||
query.data,
|
query.data,
|
||||||
query.message.chat_id,
|
query.message.chat_id,
|
||||||
query.message.message_id
|
query.message.message_id
|
||||||
)
|
)
|
||||||
await bot.answer_callback_query(query.id)
|
await bot.answer_callback_query(query.id)
|
||||||
|
print(f"[POLLING] Callback processed successfully")
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
|
print("[POLLING] Polling task cancelled")
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error in polling: {e}")
|
print(f"[POLLING] Error in polling: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
class MessageRequest(BaseModel):
|
class MessageRequest(BaseModel):
|
||||||
@@ -182,14 +223,26 @@ async def log_message(chat_id: int, message: str, success: bool, error_message:
|
|||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
async def lifespan(app: FastAPI):
|
||||||
global db_pool, bot, polling_task
|
global db_pool, bot, polling_task
|
||||||
|
print("[STARTUP] Initializing Telegram Bot API")
|
||||||
|
print(f"[STARTUP] DATABASE_URL: {DATABASE_URL}")
|
||||||
|
print(f"[STARTUP] CONTROLLER_API: {CONTROLLER_API}")
|
||||||
|
print(f"[STARTUP] TELEGRAM_BOT_TOKEN configured: {bool(TELEGRAM_BOT_TOKEN)}")
|
||||||
|
print(f"[STARTUP] TELEGRAM_CHAT_ID: {TELEGRAM_CHAT_ID}")
|
||||||
|
|
||||||
db_pool = await asyncpg.create_pool(DATABASE_URL, min_size=2, max_size=10)
|
db_pool = await asyncpg.create_pool(DATABASE_URL, min_size=2, max_size=10)
|
||||||
|
print("[STARTUP] Database pool created")
|
||||||
|
|
||||||
if TELEGRAM_BOT_TOKEN:
|
if TELEGRAM_BOT_TOKEN:
|
||||||
bot = Bot(token=TELEGRAM_BOT_TOKEN)
|
bot = Bot(token=TELEGRAM_BOT_TOKEN)
|
||||||
|
print("[STARTUP] Telegram Bot initialized")
|
||||||
polling_task = asyncio.create_task(poll_updates())
|
polling_task = asyncio.create_task(poll_updates())
|
||||||
|
print("[STARTUP] Polling task created")
|
||||||
|
else:
|
||||||
|
print("[STARTUP] WARNING: TELEGRAM_BOT_TOKEN not configured!")
|
||||||
|
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
print("[SHUTDOWN] Shutting down Telegram Bot API")
|
||||||
if polling_task:
|
if polling_task:
|
||||||
polling_task.cancel()
|
polling_task.cancel()
|
||||||
try:
|
try:
|
||||||
@@ -198,6 +251,7 @@ async def lifespan(app: FastAPI):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
await db_pool.close()
|
await db_pool.close()
|
||||||
|
print("[SHUTDOWN] Database pool closed")
|
||||||
|
|
||||||
app = FastAPI(title="Telegram Bot API", lifespan=lifespan)
|
app = FastAPI(title="Telegram Bot API", lifespan=lifespan)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user