Initial commit: SMS Forwarder project with Docker support

This commit is contained in:
zack
2025-07-17 19:30:35 +08:00
commit 152e136673
29 changed files with 3583 additions and 0 deletions

138
scripts/deploy.sh Executable file
View File

@ -0,0 +1,138 @@
#!/bin/bash
# SMS Forwarder Docker 部署脚本
set -e
echo "🚀 SMS Forwarder Docker 部署脚本"
echo "================================"
# 检查 Docker 和 Docker Compose
check_docker() {
if ! command -v docker &> /dev/null; then
echo "❌ Docker 未安装,请先安装 Docker"
exit 1
fi
if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
echo "❌ Docker Compose 未安装,请先安装 Docker Compose"
exit 1
fi
echo "✅ Docker 环境检查通过"
}
# 检查配置文件
check_config() {
if [ ! -f "config.yaml" ]; then
echo "⚠️ 配置文件不存在,从示例文件创建..."
if [ -f "config.example.yaml" ]; then
cp config.example.yaml config.yaml
echo "📝 请编辑 config.yaml 文件配置你的推送服务"
echo "是否现在编辑配置文件? (y/N)"
read -r response
if [[ "$response" =~ ^[Yy]$ ]]; then
${EDITOR:-nano} config.yaml
fi
else
echo "❌ 配置文件模板不存在"
exit 1
fi
else
echo "✅ 配置文件存在"
fi
}
# 构建镜像
build_image() {
echo "🔨 构建 Docker 镜像..."
docker build -t sms-forwarder:latest .
echo "✅ 镜像构建完成"
}
# 部署服务
deploy_service() {
echo "🚀 部署服务..."
# 停止现有服务
if docker ps -q --filter "name=sms-forwarder" | grep -q .; then
echo "⏹️ 停止现有服务..."
docker-compose down
fi
# 启动新服务
echo "▶️ 启动服务..."
docker-compose up -d
# 等待服务启动
echo "⏳ 等待服务启动..."
sleep 10
# 检查服务状态
if docker ps --filter "name=sms-forwarder" --filter "status=running" | grep -q sms-forwarder; then
echo "✅ 服务启动成功"
else
echo "❌ 服务启动失败"
docker-compose logs sms-forwarder
exit 1
fi
}
# 测试服务
test_service() {
echo "🧪 测试服务..."
# 等待服务完全启动
sleep 5
# 健康检查
if curl -f http://localhost:12152/health &> /dev/null; then
echo "✅ 健康检查通过"
else
echo "❌ 健康检查失败"
docker-compose logs sms-forwarder
exit 1
fi
# 状态检查
if curl -f http://localhost:12152/status &> /dev/null; then
echo "✅ 状态接口正常"
else
echo "❌ 状态接口异常"
fi
}
# 显示部署信息
show_info() {
echo ""
echo "🎉 部署完成!"
echo ""
echo "服务信息:"
echo " - 服务地址: http://localhost:12152"
echo " - API 文档: http://localhost:12152/docs"
echo " - 健康检查: http://localhost:12152/health"
echo " - 服务状态: http://localhost:12152/status"
echo ""
echo "管理命令:"
echo " - 查看日志: docker-compose logs -f sms-forwarder"
echo " - 重启服务: docker-compose restart sms-forwarder"
echo " - 停止服务: docker-compose down"
echo " - 查看状态: docker-compose ps"
echo ""
echo "测试命令:"
echo " - 发送测试通知: ./scripts/test-docker.sh"
echo ""
}
# 主函数
main() {
check_docker
check_config
build_image
deploy_service
test_service
show_info
}
# 运行主函数
main "$@"

86
scripts/docker-manage.sh Executable file
View File

@ -0,0 +1,86 @@
#!/bin/bash
# SMS Forwarder Docker 管理脚本
show_help() {
echo "SMS Forwarder Docker 管理脚本"
echo ""
echo "用法: $0 [命令]"
echo ""
echo "命令:"
echo " start 启动服务"
echo " stop 停止服务"
echo " restart 重启服务"
echo " status 查看服务状态"
echo " logs 查看实时日志"
echo " build 重新构建镜像"
echo " test 发送测试通知"
echo " stats 查看资源使用"
echo " shell 进入容器 shell"
echo " clean 清理未使用的镜像和容器"
echo " deploy 完整部署流程"
echo " help 显示此帮助信息"
}
case "$1" in
start)
echo "🚀 启动 SMS Forwarder 服务..."
docker-compose up -d
;;
stop)
echo "⏹️ 停止 SMS Forwarder 服务..."
docker-compose down
;;
restart)
echo "🔄 重启 SMS Forwarder 服务..."
docker-compose restart sms-forwarder
;;
status)
echo "📊 SMS Forwarder 服务状态:"
docker-compose ps
echo ""
echo "容器详细信息:"
docker inspect sms-forwarder --format='{{.State.Status}}: {{.State.StartedAt}}'
;;
logs)
echo "📋 SMS Forwarder 实时日志 (Ctrl+C 退出):"
docker-compose logs -f sms-forwarder
;;
build)
echo "🔨 重新构建镜像..."
docker-compose build --no-cache sms-forwarder
;;
test)
echo "🧪 发送测试通知..."
./scripts/test-docker.sh
;;
stats)
echo "💾 资源使用统计:"
docker stats sms-forwarder --no-stream
;;
shell)
echo "🐚 进入容器 shell..."
docker-compose exec sms-forwarder /bin/bash
;;
clean)
echo "🧹 清理未使用的 Docker 资源..."
docker system prune -f
docker image prune -f
;;
deploy)
echo "🚀 执行完整部署流程..."
./scripts/deploy.sh
;;
help|--help|-h)
show_help
;;
"")
show_help
;;
*)
echo "❌ 未知命令: $1"
echo ""
show_help
exit 1
;;
esac

128
scripts/install.sh Executable file
View File

@ -0,0 +1,128 @@
#!/bin/bash
# SMS Forwarder 安装脚本
set -e
echo "🚀 开始安装 SMS Forwarder..."
# 检查 Python 版本
check_python() {
if command -v python3 &> /dev/null; then
PYTHON_VERSION=$(python3 -c 'import sys; print(".".join(map(str, sys.version_info[:2])))')
if [[ $(echo "$PYTHON_VERSION >= 3.10" | bc -l) -eq 1 ]]; then
echo "✅ Python $PYTHON_VERSION 已安装"
else
echo "❌ 需要 Python 3.10 或更高版本,当前版本: $PYTHON_VERSION"
exit 1
fi
else
echo "❌ 未找到 Python 3请先安装 Python 3.10+"
exit 1
fi
}
# 安装 uv
install_uv() {
if command -v uv &> /dev/null; then
echo "✅ uv 已安装"
else
echo "📦 安装 uv..."
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.cargo/env
fi
}
# 安装依赖
install_dependencies() {
echo "📦 安装项目依赖..."
uv sync
}
# 创建配置文件
setup_config() {
if [ ! -f "config.yaml" ]; then
echo "⚙️ 创建配置文件..."
cp config.example.yaml config.yaml
echo "📝 请编辑 config.yaml 文件配置你的推送服务"
else
echo "✅ 配置文件已存在"
fi
}
# 创建必要目录
create_directories() {
echo "📁 创建必要目录..."
mkdir -p logs
mkdir -p data
}
# 生成 API 密钥
generate_api_key() {
if command -v python3 &> /dev/null; then
API_KEY=$(python3 -c "import secrets; print(secrets.token_urlsafe(32))")
echo "🔑 生成的 API 密钥: $API_KEY"
echo "请将此密钥添加到 config.yaml 文件中的 server.api_key 字段"
fi
}
# 创建 systemd 服务文件
create_systemd_service() {
read -p "是否创建 systemd 服务? (y/N): " create_service
if [[ $create_service =~ ^[Yy]$ ]]; then
CURRENT_DIR=$(pwd)
USER=$(whoami)
cat > sms-forwarder.service << EOF
[Unit]
Description=SMS Forwarder Service
After=network.target
[Service]
Type=simple
User=$USER
WorkingDirectory=$CURRENT_DIR
Environment=PATH=$CURRENT_DIR/.venv/bin
ExecStart=$CURRENT_DIR/.venv/bin/python -m sms_forwarder.main
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
echo "📄 systemd 服务文件已创建: sms-forwarder.service"
echo "运行以下命令安装服务:"
echo " sudo cp sms-forwarder.service /etc/systemd/system/"
echo " sudo systemctl daemon-reload"
echo " sudo systemctl enable sms-forwarder"
echo " sudo systemctl start sms-forwarder"
fi
}
# 主安装流程
main() {
echo "SMS Forwarder 安装程序"
echo "======================"
check_python
install_uv
install_dependencies
create_directories
setup_config
generate_api_key
create_systemd_service
echo ""
echo "🎉 安装完成!"
echo ""
echo "下一步:"
echo "1. 编辑 config.yaml 文件配置推送服务"
echo "2. 运行 'uv run sms-forwarder' 启动服务器"
echo "3. 访问 http://localhost:8000/docs 查看 API 文档"
echo "4. 参考 docs/iphone-setup.md 配置 iPhone 快捷指令"
echo ""
}
# 运行主函数
main "$@"

96
scripts/manage.sh Executable file
View File

@ -0,0 +1,96 @@
#!/bin/bash
# SMS Forwarder 管理脚本
SERVICE_NAME="sms-forwarder"
show_help() {
echo "SMS Forwarder 管理脚本"
echo ""
echo "用法: $0 [命令]"
echo ""
echo "命令:"
echo " start 启动服务"
echo " stop 停止服务"
echo " restart 重启服务"
echo " status 查看服务状态"
echo " logs 查看实时日志"
echo " enable 启用开机自启"
echo " disable 禁用开机自启"
echo " test 发送测试通知"
echo " update 更新依赖"
echo " config 编辑配置文件"
echo " install 安装 systemd 服务"
echo " help 显示此帮助信息"
}
case "$1" in
start)
echo "🚀 启动 SMS Forwarder 服务..."
sudo systemctl start $SERVICE_NAME
;;
stop)
echo "⏹️ 停止 SMS Forwarder 服务..."
sudo systemctl stop $SERVICE_NAME
;;
restart)
echo "🔄 重启 SMS Forwarder 服务..."
sudo systemctl restart $SERVICE_NAME
;;
status)
echo "📊 SMS Forwarder 服务状态:"
sudo systemctl status $SERVICE_NAME --no-pager
;;
logs)
echo "📋 SMS Forwarder 实时日志 (Ctrl+C 退出):"
sudo journalctl -u $SERVICE_NAME -f
;;
enable)
echo "✅ 启用 SMS Forwarder 开机自启..."
sudo systemctl enable $SERVICE_NAME
;;
disable)
echo "❌ 禁用 SMS Forwarder 开机自启..."
sudo systemctl disable $SERVICE_NAME
;;
test)
echo "🧪 发送测试通知..."
if [ -f "config.yaml" ]; then
API_KEY=$(grep "api_key:" config.yaml | awk '{print $2}' | tr -d '"')
uv run python scripts/test_notification.py http://localhost:12152 "$API_KEY"
else
echo "❌ 配置文件不存在"
fi
;;
update)
echo "📦 更新依赖..."
uv sync
echo "🔄 重启服务以应用更新..."
sudo systemctl restart $SERVICE_NAME
;;
config)
echo "⚙️ 编辑配置文件..."
${EDITOR:-nano} config.yaml
echo "是否重启服务以应用配置? (y/N)"
read -r response
if [[ "$response" =~ ^[Yy]$ ]]; then
sudo systemctl restart $SERVICE_NAME
fi
;;
install)
echo "🔧 安装 systemd 服务..."
./scripts/setup-systemd.sh
;;
help|--help|-h)
show_help
;;
"")
show_help
;;
*)
echo "❌ 未知命令: $1"
echo ""
show_help
exit 1
;;
esac

71
scripts/setup-systemd.sh Executable file
View File

@ -0,0 +1,71 @@
#!/bin/bash
# SMS Forwarder systemd 服务安装脚本
set -e
echo "🔧 配置 SMS Forwarder systemd 服务..."
# 获取当前用户和路径
CURRENT_USER=$(whoami)
CURRENT_DIR=$(pwd)
SERVICE_FILE="sms-forwarder.service"
# 检查是否在正确的目录
if [ ! -f "pyproject.toml" ] || [ ! -f "config.yaml" ]; then
echo "❌ 请在项目根目录运行此脚本"
exit 1
fi
# 检查 uv 虚拟环境
if [ ! -d ".venv" ]; then
echo "📦 创建虚拟环境..."
uv sync
fi
# 获取虚拟环境路径
VENV_PATH="$CURRENT_DIR/.venv"
if [ ! -f "$VENV_PATH/bin/python" ]; then
echo "❌ 虚拟环境未找到,请先运行 'uv sync'"
exit 1
fi
# 创建日志和数据目录
mkdir -p logs data
# 更新服务文件中的路径
echo "📝 更新服务文件配置..."
sed -i "s|your-username|$CURRENT_USER|g" $SERVICE_FILE
sed -i "s|/path/to/notification|$CURRENT_DIR|g" $SERVICE_FILE
# 复制服务文件到系统目录
echo "📋 安装 systemd 服务文件..."
sudo cp $SERVICE_FILE /etc/systemd/system/
# 重新加载 systemd
echo "🔄 重新加载 systemd..."
sudo systemctl daemon-reload
# 启用服务
echo "✅ 启用 SMS Forwarder 服务..."
sudo systemctl enable sms-forwarder
# 启动服务
echo "🚀 启动 SMS Forwarder 服务..."
sudo systemctl start sms-forwarder
# 检查状态
echo "📊 检查服务状态..."
sudo systemctl status sms-forwarder --no-pager
echo ""
echo "🎉 SMS Forwarder 服务安装完成!"
echo ""
echo "常用命令:"
echo " 查看状态: sudo systemctl status sms-forwarder"
echo " 查看日志: sudo journalctl -u sms-forwarder -f"
echo " 重启服务: sudo systemctl restart sms-forwarder"
echo " 停止服务: sudo systemctl stop sms-forwarder"
echo " 禁用服务: sudo systemctl disable sms-forwarder"
echo ""
echo "服务将在系统重启后自动启动。"

114
scripts/test-docker.sh Executable file
View File

@ -0,0 +1,114 @@
#!/bin/bash
# Docker 环境测试脚本
set -e
echo "🧪 SMS Forwarder Docker 测试"
echo "============================"
# 检查服务是否运行
check_service() {
if ! docker ps --filter "name=sms-forwarder" --filter "status=running" | grep -q sms-forwarder; then
echo "❌ SMS Forwarder 服务未运行"
echo "请先运行: docker-compose up -d"
exit 1
fi
echo "✅ 服务正在运行"
}
# 获取 API 密钥
get_api_key() {
if [ -f "config.yaml" ]; then
API_KEY=$(grep "api_key:" config.yaml | awk '{print $2}' | tr -d '"')
if [ -z "$API_KEY" ]; then
echo "❌ 无法从配置文件获取 API 密钥"
exit 1
fi
echo "✅ 获取到 API 密钥"
else
echo "❌ 配置文件不存在"
exit 1
fi
}
# 测试健康检查
test_health() {
echo "🔍 测试健康检查..."
if curl -f http://localhost:12152/health &> /dev/null; then
echo "✅ 健康检查通过"
else
echo "❌ 健康检查失败"
return 1
fi
}
# 测试状态接口
test_status() {
echo "📊 测试状态接口..."
STATUS=$(curl -s http://localhost:12152/status)
if [ $? -eq 0 ]; then
echo "✅ 状态接口正常"
echo "服务状态: $STATUS"
else
echo "❌ 状态接口异常"
return 1
fi
}
# 测试通知发送
test_notification() {
echo "📱 测试通知发送..."
RESPONSE=$(curl -s -X POST "http://localhost:12152/notify/simple" \
-H "Content-Type: application/json" \
-d "{
\"api_key\": \"$API_KEY\",
\"content\": \"Docker 测试通知 - $(date)\",
\"sender\": \"Docker 测试\"
}")
if echo "$RESPONSE" | grep -q '"success":true'; then
echo "✅ 通知发送成功"
echo "响应: $RESPONSE"
else
echo "❌ 通知发送失败"
echo "响应: $RESPONSE"
return 1
fi
}
# 显示容器信息
show_container_info() {
echo ""
echo "📋 容器信息:"
docker-compose ps
echo ""
echo "💾 资源使用:"
docker stats sms-forwarder --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"
}
# 主函数
main() {
check_service
get_api_key
echo ""
echo "开始测试..."
test_health
test_status
test_notification
echo ""
echo "🎉 所有测试通过!"
show_container_info
echo ""
echo "如果你的 Android 设备收到了通知,说明 Docker 部署成功!"
}
# 运行主函数
main "$@"

125
scripts/test_notification.py Executable file
View File

@ -0,0 +1,125 @@
#!/usr/bin/env python3
"""测试通知发送脚本."""
import json
import sys
from datetime import datetime
import requests
def test_notification(server_url: str, api_key: str):
"""测试发送通知."""
# 测试简化版 API
simple_test_data = {
"api_key": api_key,
"content": "这是一条测试短信,用于验证通知转发功能是否正常工作。",
"sender": "测试发送者"
}
try:
print(f"🔄 正在向 {server_url} 发送测试通知...")
# 发送请求到简化版 API
response = requests.post(
f"{server_url}/notify/simple",
json=simple_test_data,
headers={"Content-Type": "application/json"},
timeout=10
)
# 检查响应
if response.status_code == 200:
result = response.json()
if result.get("success"):
print("✅ 测试通知发送成功!")
print(f"📱 请检查你的 Android 设备是否收到通知")
else:
print(f"❌ 通知发送失败: {result.get('message')}")
return False
else:
print(f"❌ HTTP 请求失败: {response.status_code}")
print(f"响应内容: {response.text}")
return False
except requests.exceptions.ConnectionError:
print(f"❌ 无法连接到服务器 {server_url}")
print("请确认服务器正在运行且地址正确")
return False
except requests.exceptions.Timeout:
print("❌ 请求超时")
return False
except Exception as e:
print(f"❌ 发生错误: {e}")
return False
return True
def test_server_status(server_url: str):
"""测试服务器状态."""
try:
print(f"🔄 检查服务器状态...")
# 健康检查
health_response = requests.get(f"{server_url}/health", timeout=5)
if health_response.status_code == 200:
print("✅ 服务器健康检查通过")
else:
print(f"⚠️ 健康检查失败: {health_response.status_code}")
# 状态信息
status_response = requests.get(f"{server_url}/status", timeout=5)
if status_response.status_code == 200:
status = status_response.json()
print(f"📊 服务器状态:")
print(f" 版本: {status.get('version')}")
print(f" 运行时间: {status.get('uptime', 0):.2f}")
print(f" 已发送通知: {status.get('notifications_sent', 0)}")
print(f" 失败通知: {status.get('notifications_failed', 0)}")
else:
print(f"⚠️ 获取状态信息失败: {status_response.status_code}")
except Exception as e:
print(f"❌ 检查服务器状态时出错: {e}")
return False
return True
def main():
"""主函数."""
if len(sys.argv) < 3:
print("使用方法: python test_notification.py <server_url> <api_key>")
print("示例: python test_notification.py http://localhost:8000 your-api-key")
sys.exit(1)
server_url = sys.argv[1].rstrip('/')
api_key = sys.argv[2]
print("SMS Forwarder 通知测试")
print("=" * 30)
# 测试服务器状态
if not test_server_status(server_url):
print("❌ 服务器状态检查失败")
sys.exit(1)
print()
# 测试通知发送
if test_notification(server_url, api_key):
print("\n🎉 所有测试通过!")
print("如果你的 Android 设备收到了通知,说明配置正确。")
else:
print("\n❌ 测试失败")
print("请检查:")
print("1. 服务器配置是否正确")
print("2. API 密钥是否正确")
print("3. 推送服务是否正确配置")
sys.exit(1)
if __name__ == "__main__":
main()