- Python: ruff --fix 修復 280 個 lint 錯誤 - lewooogo-core: src/ 目錄未追蹤,導致 CI eslint 失敗 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
171 lines
4.9 KiB
Python
171 lines
4.9 KiB
Python
"""
|
||
Notification Manager
|
||
====================
|
||
Phase 6: leWOOOgo Output Plugins
|
||
|
||
管理所有 NotificationProvider,統一發送介面
|
||
"""
|
||
|
||
from src.core.logging import get_logger
|
||
|
||
from .base import (
|
||
NotificationMessage,
|
||
NotificationProvider,
|
||
NotificationResult,
|
||
NotificationStatus,
|
||
)
|
||
from .discord import DiscordWebhookProvider
|
||
|
||
logger = get_logger("awoooi.notifications.manager")
|
||
|
||
|
||
class NotificationManager:
|
||
"""
|
||
通知管理器
|
||
|
||
管理多個 NotificationProvider,支援:
|
||
- 同時發送至多個頻道
|
||
- 優雅降級 (單一 Provider 失敗不影響其他)
|
||
- 結果追蹤
|
||
"""
|
||
|
||
def __init__(self):
|
||
self._providers: list[NotificationProvider] = []
|
||
self._initialized = False
|
||
|
||
def register(self, provider: NotificationProvider) -> None:
|
||
"""註冊 Provider"""
|
||
if provider.enabled:
|
||
self._providers.append(provider)
|
||
logger.info(
|
||
"notification_provider_registered",
|
||
provider=provider.name,
|
||
enabled=provider.enabled,
|
||
)
|
||
else:
|
||
logger.warning(
|
||
"notification_provider_disabled",
|
||
provider=provider.name,
|
||
)
|
||
|
||
def initialize(self) -> None:
|
||
"""初始化所有 Provider"""
|
||
if self._initialized:
|
||
return
|
||
|
||
# 註冊 Discord
|
||
discord = DiscordWebhookProvider()
|
||
self.register(discord)
|
||
|
||
# TODO: 註冊其他 Provider
|
||
# slack = SlackWebhookProvider()
|
||
# self.register(slack)
|
||
|
||
self._initialized = True
|
||
logger.info(
|
||
"notification_manager_initialized",
|
||
provider_count=len(self._providers),
|
||
providers=[p.name for p in self._providers],
|
||
)
|
||
|
||
async def send_all(self, message: NotificationMessage) -> list[NotificationResult]:
|
||
"""
|
||
發送通知至所有已註冊的 Provider
|
||
|
||
Returns:
|
||
list[NotificationResult]: 各 Provider 的發送結果
|
||
"""
|
||
if not self._initialized:
|
||
self.initialize()
|
||
|
||
if not self._providers:
|
||
logger.warning("no_notification_providers_available")
|
||
return [
|
||
NotificationResult(
|
||
status=NotificationStatus.SKIPPED,
|
||
provider="none",
|
||
message="No notification providers configured",
|
||
)
|
||
]
|
||
|
||
results = []
|
||
for provider in self._providers:
|
||
try:
|
||
result = await provider.send(message)
|
||
results.append(result)
|
||
logger.info(
|
||
"notification_sent",
|
||
provider=provider.name,
|
||
status=result.status.value,
|
||
)
|
||
except Exception as e:
|
||
logger.exception(
|
||
"notification_send_failed",
|
||
provider=provider.name,
|
||
error=str(e),
|
||
)
|
||
results.append(
|
||
NotificationResult(
|
||
status=NotificationStatus.FAILED,
|
||
provider=provider.name,
|
||
message="Exception during send",
|
||
error=str(e),
|
||
)
|
||
)
|
||
|
||
return results
|
||
|
||
async def test_all(self) -> dict[str, bool]:
|
||
"""
|
||
測試所有 Provider 連線
|
||
|
||
Returns:
|
||
dict[str, bool]: Provider 名稱 → 連線狀態
|
||
"""
|
||
if not self._initialized:
|
||
self.initialize()
|
||
|
||
results = {}
|
||
for provider in self._providers:
|
||
try:
|
||
results[provider.name] = await provider.test_connection()
|
||
except Exception as e:
|
||
logger.error(
|
||
"notification_test_failed",
|
||
provider=provider.name,
|
||
error=str(e),
|
||
)
|
||
results[provider.name] = False
|
||
|
||
return results
|
||
|
||
async def close(self) -> None:
|
||
"""關閉所有 Provider"""
|
||
for provider in self._providers:
|
||
if hasattr(provider, "close"):
|
||
await provider.close()
|
||
|
||
|
||
# =============================================================================
|
||
# Singleton Instance
|
||
# =============================================================================
|
||
|
||
_notification_manager: NotificationManager | None = None
|
||
|
||
|
||
def get_notification_manager() -> NotificationManager:
|
||
"""取得 NotificationManager 單例"""
|
||
global _notification_manager
|
||
if _notification_manager is None:
|
||
_notification_manager = NotificationManager()
|
||
_notification_manager.initialize()
|
||
return _notification_manager
|
||
|
||
|
||
async def close_notification_manager() -> None:
|
||
"""關閉 NotificationManager"""
|
||
global _notification_manager
|
||
if _notification_manager:
|
||
await _notification_manager.close()
|
||
_notification_manager = None
|