- 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
326 lines
7.7 KiB
Go
326 lines
7.7 KiB
Go
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
|
|
}
|