200 lines
5.6 KiB
Python
200 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
通知模块
|
||
负责在重要事件发生时发送通知
|
||
"""
|
||
|
||
import sys
|
||
import platform
|
||
from typing import Optional
|
||
from abc import ABC, abstractmethod
|
||
|
||
|
||
class Notifier(ABC):
|
||
"""通知器抽象基类"""
|
||
|
||
@abstractmethod
|
||
def send(self, title: str, message: str):
|
||
"""
|
||
发送通知
|
||
|
||
Args:
|
||
title: 通知标题
|
||
message: 通知内容
|
||
"""
|
||
pass
|
||
|
||
|
||
class ConsoleNotifier(Notifier):
|
||
"""控制台通知器"""
|
||
|
||
def send(self, title: str, message: str):
|
||
"""在控制台显示通知"""
|
||
separator = "=" * 60
|
||
print(f"\n{separator}")
|
||
print(f"【{title}】")
|
||
print(f"{message}")
|
||
print(f"{separator}\n")
|
||
|
||
|
||
class DesktopNotifier(Notifier):
|
||
"""桌面通知器"""
|
||
|
||
def __init__(self):
|
||
"""初始化桌面通知器"""
|
||
self.os_type = platform.system().lower()
|
||
self.enabled = True
|
||
|
||
# 尝试导入通知库
|
||
if self.os_type == "windows":
|
||
try:
|
||
import win10toast
|
||
self.toaster = win10toast.ToastNotifier()
|
||
except ImportError:
|
||
self.enabled = False
|
||
elif self.os_type == "linux":
|
||
try:
|
||
import notify2
|
||
notify2.init("网络监控器")
|
||
except ImportError:
|
||
self.enabled = False
|
||
elif self.os_type == "darwin":
|
||
try:
|
||
import pync
|
||
except ImportError:
|
||
self.enabled = False
|
||
|
||
def send(self, title: str, message: str):
|
||
"""发送桌面通知"""
|
||
if not self.enabled:
|
||
return
|
||
|
||
try:
|
||
if self.os_type == "windows":
|
||
self.toaster.show_notification(
|
||
title,
|
||
message,
|
||
duration=10
|
||
)
|
||
elif self.os_type == "linux":
|
||
import notify2
|
||
notification = notify2.Notification(title, message)
|
||
notification.show()
|
||
elif self.os_type == "darwin":
|
||
import pync
|
||
pync.notify(message, title=title)
|
||
except Exception as e:
|
||
print(f"发送桌面通知失败: {e}")
|
||
|
||
|
||
class EmailNotifier(Notifier):
|
||
"""邮件通知器(示例,需要配置SMTP)"""
|
||
|
||
def __init__(self, smtp_server: str = None, smtp_port: int = None,
|
||
username: str = None, password: str = None,
|
||
from_email: str = None, to_email: str = None):
|
||
"""
|
||
初始化邮件通知器
|
||
|
||
Args:
|
||
smtp_server: SMTP服务器地址
|
||
smtp_port: SMTP端口
|
||
username: 用户名
|
||
password: 密码
|
||
from_email: 发件人邮箱
|
||
to_email: 收件人邮箱
|
||
"""
|
||
self.smtp_server = smtp_server
|
||
self.smtp_port = smtp_port
|
||
self.username = username
|
||
self.password = password
|
||
self.from_email = from_email
|
||
self.to_email = to_email
|
||
self.enabled = all([smtp_server, smtp_port, username, password, from_email, to_email])
|
||
|
||
def send(self, title: str, message: str):
|
||
"""发送邮件通知"""
|
||
if not self.enabled:
|
||
print("邮件通知未配置,跳过发送")
|
||
return
|
||
|
||
try:
|
||
import smtplib
|
||
from email.mime.text import MIMEText
|
||
from email.mime.multipart import MIMEMultipart
|
||
|
||
# 创建邮件
|
||
msg = MIMEMultipart()
|
||
msg['From'] = self.from_email
|
||
msg['To'] = self.to_email
|
||
msg['Subject'] = title
|
||
|
||
# 添加邮件正文
|
||
msg.attach(MIMEText(message, 'plain', 'utf-8'))
|
||
|
||
# 发送邮件
|
||
with smtplib.SMTP(self.smtp_server, self.smtp_port) as server:
|
||
server.starttls()
|
||
server.login(self.username, self.password)
|
||
server.send_message(msg)
|
||
|
||
print(f"邮件通知已发送至 {self.to_email}")
|
||
|
||
except Exception as e:
|
||
print(f"发送邮件通知失败: {e}")
|
||
|
||
|
||
class NotificationManager:
|
||
"""通知管理器"""
|
||
|
||
def __init__(self, enable_console: bool = True, enable_desktop: bool = False):
|
||
"""
|
||
初始化通知管理器
|
||
|
||
Args:
|
||
enable_console: 是否启用控制台通知
|
||
enable_desktop: 是否启用桌面通知
|
||
"""
|
||
self.notifiers: list[Notifier] = []
|
||
|
||
if enable_console:
|
||
self.notifiers.append(ConsoleNotifier())
|
||
|
||
if enable_desktop:
|
||
self.notifiers.append(DesktopNotifier())
|
||
|
||
def add_notifier(self, notifier: Notifier):
|
||
"""
|
||
添加通知器
|
||
|
||
Args:
|
||
notifier: 通知器实例
|
||
"""
|
||
self.notifiers.append(notifier)
|
||
|
||
def notify(self, title: str, message: str):
|
||
"""
|
||
发送通知到所有通知器
|
||
|
||
Args:
|
||
title: 通知标题
|
||
message: 通知内容
|
||
"""
|
||
for notifier in self.notifiers:
|
||
notifier.send(title, message)
|
||
|
||
def notify_connection_lost(self, ip: str, duration: float):
|
||
"""通知连接丢失"""
|
||
self.notify(
|
||
"网络连接丢失",
|
||
f"无法连接到 {ip}\n已断开 {duration:.1f} 秒"
|
||
)
|
||
|
||
def notify_shutdown(self, reason: str):
|
||
"""通知系统即将关机"""
|
||
self.notify(
|
||
"系统即将关机",
|
||
f"原因: {reason}\n请保存所有工作!"
|
||
)
|