initial commit: Go version of SMS Receiver with fixed template rendering
- Implemented all core features from Python version - Fixed int64/int type compatibility in template functions - Added login authentication, SMS receiving, statistics, logs - Independent database: sms_receiver_go.db - Fixed frontend display issues for message list and statistics
This commit is contained in:
325
database/database.go
Normal file
325
database/database.go
Normal file
@@ -0,0 +1,325 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"sms-receiver-go/config"
|
||||
"sms-receiver-go/models"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
var db *sql.DB
|
||||
|
||||
// Init 初始化数据库
|
||||
func Init(cfg *config.DatabaseConfig) error {
|
||||
var err error
|
||||
db, err = sql.Open("sqlite3", cfg.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("打开数据库失败: %w", err)
|
||||
}
|
||||
|
||||
if err = db.Ping(); err != nil {
|
||||
return fmt.Errorf("数据库连接失败: %w", err)
|
||||
}
|
||||
|
||||
// 创建表
|
||||
if err = createTables(); err != nil {
|
||||
return fmt.Errorf("创建表失败: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("数据库初始化成功: %s", cfg.Path)
|
||||
return nil
|
||||
}
|
||||
|
||||
// createTables 创建数据表
|
||||
func createTables() error {
|
||||
// 短信消息表
|
||||
createMessagesSQL := `
|
||||
CREATE TABLE IF NOT EXISTS sms_messages (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
from_number TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
timestamp INTEGER NOT NULL,
|
||||
device_info TEXT,
|
||||
sim_info TEXT,
|
||||
sign_verified INTEGER,
|
||||
ip_address TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`
|
||||
|
||||
// 接收日志表
|
||||
createLogsSQL := `
|
||||
CREATE TABLE IF NOT EXISTS receive_logs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
from_number TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
timestamp INTEGER NOT NULL,
|
||||
sign TEXT,
|
||||
sign_valid INTEGER,
|
||||
ip_address TEXT,
|
||||
status TEXT NOT NULL,
|
||||
error_message TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`
|
||||
|
||||
// 创建索引
|
||||
createIndexesSQL := `
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_from ON sms_messages(from_number);
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_timestamp ON sms_messages(timestamp);
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_created ON sms_messages(created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_logs_created ON receive_logs(created_at);
|
||||
`
|
||||
|
||||
statements := []string{createMessagesSQL, createLogsSQL, createIndexesSQL}
|
||||
for _, stmt := range statements {
|
||||
if _, err := db.Exec(stmt); err != nil {
|
||||
return fmt.Errorf("执行 SQL 失败: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertMessage 插入短信消息
|
||||
func InsertMessage(msg *models.SMSMessage) (int64, error) {
|
||||
result, err := db.Exec(`
|
||||
INSERT INTO sms_messages (from_number, content, timestamp, device_info, sim_info, sign_verified, ip_address)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
`,
|
||||
msg.FromNumber,
|
||||
msg.Content,
|
||||
msg.Timestamp,
|
||||
msg.DeviceInfo,
|
||||
msg.SIMInfo,
|
||||
msg.SignVerified,
|
||||
msg.IPAddress,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("插入消息失败: %w", err)
|
||||
}
|
||||
return result.LastInsertId()
|
||||
}
|
||||
|
||||
// InsertLog 插入接收日志
|
||||
func InsertLog(log *models.ReceiveLog) (int64, error) {
|
||||
result, err := db.Exec(`
|
||||
INSERT INTO receive_logs (from_number, content, timestamp, sign, sign_valid, ip_address, status, error_message)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`,
|
||||
log.FromNumber,
|
||||
log.Content,
|
||||
log.Timestamp,
|
||||
log.Sign,
|
||||
log.SignValid,
|
||||
log.IPAddress,
|
||||
log.Status,
|
||||
log.ErrorMessage,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("插入日志失败: %w", err)
|
||||
}
|
||||
return result.LastInsertId()
|
||||
}
|
||||
|
||||
// GetMessages 获取短信列表
|
||||
func GetMessages(page, limit int, from string, search string) ([]models.SMSMessage, int64, error) {
|
||||
offset := (page - 1) * limit
|
||||
|
||||
// 构建查询条件
|
||||
var conditions []string
|
||||
var args []interface{}
|
||||
|
||||
if from != "" {
|
||||
conditions = append(conditions, "from_number = ?")
|
||||
args = append(args, from)
|
||||
}
|
||||
if search != "" {
|
||||
conditions = append(conditions, "(from_number LIKE ? OR content LIKE ?)")
|
||||
args = append(args, "%"+search+"%", "%"+search+"%")
|
||||
}
|
||||
|
||||
whereClause := ""
|
||||
if len(conditions) > 0 {
|
||||
whereClause = "WHERE " + strings.Join(conditions, " AND ")
|
||||
}
|
||||
|
||||
// 查询总数
|
||||
var total int64
|
||||
countSQL := fmt.Sprintf("SELECT COUNT(*) FROM sms_messages %s", whereClause)
|
||||
if err := db.QueryRow(countSQL, args...).Scan(&total); err != nil {
|
||||
return nil, 0, fmt.Errorf("查询总数失败: %w", err)
|
||||
}
|
||||
|
||||
// 查询数据(按短信时间戳排序,与 Python 版本一致)
|
||||
querySQL := fmt.Sprintf(`
|
||||
SELECT id, from_number, content, timestamp, device_info, sim_info, sign_verified, ip_address, created_at
|
||||
FROM sms_messages
|
||||
%s
|
||||
ORDER BY timestamp DESC, id DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`, whereClause)
|
||||
|
||||
args = append(args, limit, offset)
|
||||
rows, err := db.Query(querySQL, args...)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("查询消息失败: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var messages []models.SMSMessage
|
||||
for rows.Next() {
|
||||
var msg models.SMSMessage
|
||||
err := rows.Scan(
|
||||
&msg.ID,
|
||||
&msg.FromNumber,
|
||||
&msg.Content,
|
||||
&msg.Timestamp,
|
||||
&msg.DeviceInfo,
|
||||
&msg.SIMInfo,
|
||||
&msg.SignVerified,
|
||||
&msg.IPAddress,
|
||||
&msg.CreatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("扫描消息失败: %w", err)
|
||||
}
|
||||
messages = append(messages, msg)
|
||||
}
|
||||
|
||||
return messages, total, nil
|
||||
}
|
||||
|
||||
// GetMessageByID 根据 ID 获取消息详情
|
||||
func GetMessageByID(id int64) (*models.SMSMessage, error) {
|
||||
var msg models.SMSMessage
|
||||
err := db.QueryRow(`
|
||||
SELECT id, from_number, content, timestamp, device_info, sim_info, sign_verified, ip_address, created_at
|
||||
FROM sms_messages WHERE id = ?
|
||||
`, id).Scan(
|
||||
&msg.ID,
|
||||
&msg.FromNumber,
|
||||
&msg.Content,
|
||||
&msg.Timestamp,
|
||||
&msg.DeviceInfo,
|
||||
&msg.SIMInfo,
|
||||
&msg.SignVerified,
|
||||
&msg.IPAddress,
|
||||
&msg.CreatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf("查询消息失败: %w", err)
|
||||
}
|
||||
return &msg, nil
|
||||
}
|
||||
|
||||
// GetStatistics 获取统计信息
|
||||
func GetStatistics() (*models.Statistics, error) {
|
||||
stats := &models.Statistics{}
|
||||
|
||||
// 总数
|
||||
if err := db.QueryRow("SELECT COUNT(*) FROM sms_messages").Scan(&stats.Total); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 今日数量
|
||||
today := time.Now().Format("2006-01-02")
|
||||
if err := db.QueryRow("SELECT COUNT(*) FROM sms_messages WHERE date(created_at) = ?", today).Scan(&stats.Today); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 本周数量
|
||||
weekStart := time.Now().AddDate(0, 0, -int(time.Now().Weekday())+1).Format("2006-01-02")
|
||||
if err := db.QueryRow("SELECT COUNT(*) FROM sms_messages WHERE created_at >= ?", weekStart).Scan(&stats.Week); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 签名验证通过数量
|
||||
if err := db.QueryRow("SELECT COUNT(*) FROM sms_messages WHERE sign_verified = 1").Scan(&stats.Verified); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 签名验证未通过数量
|
||||
if err := db.QueryRow("SELECT COUNT(*) FROM sms_messages WHERE sign_verified = 0").Scan(&stats.Unverified); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// GetLogs 获取接收日志
|
||||
func GetLogs(page, limit int) ([]models.ReceiveLog, int64, error) {
|
||||
offset := (page - 1) * limit
|
||||
|
||||
// 查询总数
|
||||
var total int64
|
||||
if err := db.QueryRow("SELECT COUNT(*) FROM receive_logs").Scan(&total); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
rows, err := db.Query(`
|
||||
SELECT id, from_number, content, timestamp, sign, sign_valid, ip_address, status, error_message, created_at
|
||||
FROM receive_logs
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`, limit, offset)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var logs []models.ReceiveLog
|
||||
for rows.Next() {
|
||||
var log models.ReceiveLog
|
||||
err := rows.Scan(
|
||||
&log.ID,
|
||||
&log.FromNumber,
|
||||
&log.Content,
|
||||
&log.Timestamp,
|
||||
&log.Sign,
|
||||
&log.SignValid,
|
||||
&log.IPAddress,
|
||||
&log.Status,
|
||||
&log.ErrorMessage,
|
||||
&log.CreatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
logs = append(logs, log)
|
||||
}
|
||||
|
||||
return logs, total, nil
|
||||
}
|
||||
|
||||
// CleanupOldMessages 清理旧消息
|
||||
func CleanupOldMessages(days int) (int64, error) {
|
||||
cutoff := time.Now().AddDate(0, 0, -days).Format("2006-01-02 15:04:05")
|
||||
result, err := db.Exec("DELETE FROM sms_messages WHERE created_at < ?", cutoff)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.RowsAffected()
|
||||
}
|
||||
|
||||
// GetDB 获取数据库实例
|
||||
func GetDB() *sql.DB {
|
||||
return db
|
||||
}
|
||||
|
||||
// Close 关闭数据库连接
|
||||
func Close() error {
|
||||
if db != nil {
|
||||
return db.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user