Files
personal-experiment/notifier.py
T
2026-03-06 11:26:35 +08:00

200 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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请保存所有工作!"
)