You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
RTSPtoWeb/database.go

272 lines
7.4 KiB
Go

package main
import (
"database/sql"
"fmt"
"time"
_ "github.com/denisenkom/go-mssqldb"
_ "github.com/go-sql-driver/mysql"
"github.com/google/uuid"
)
// DatabaseConfig 数据库配置结构
type DatabaseConfig struct {
Enabled bool `json:"enabled"`
Type string `json:"type"` // mysql 或 sqlserver
Host string `json:"host"`
Port int `json:"port"`
Database string `json:"database"`
Username string `json:"username"`
Password string `json:"password"`
SSLMode string `json:"ssl_mode,omitempty"` // for mysql
}
// Camera 摄像头数据库模型
type Camera struct {
ID string `json:"id" db:"id"`
Name string `json:"name" db:"name"`
IP string `json:"ip" db:"ip"`
Username string `json:"username" db:"username"`
Password string `json:"password" db:"password"`
RTSPURL string `json:"rtsp_url" db:"rtsp_url"`
Enabled bool `json:"enabled" db:"enabled"`
OnDemand bool `json:"on_demand" db:"on_demand"`
Audio bool `json:"audio" db:"audio"`
Debug bool `json:"debug" db:"debug"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}
// DatabaseManager 数据库管理器
type DatabaseManager struct {
db *sql.DB
config DatabaseConfig
}
// NewDatabaseManager 创建数据库管理器
func NewDatabaseManager(config DatabaseConfig) (*DatabaseManager, error) {
if !config.Enabled {
return nil, nil
}
var dsn string
switch config.Type {
case "mysql":
dsn = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
config.Username, config.Password, config.Host, config.Port, config.Database)
if config.SSLMode != "" {
dsn += "&tls=" + config.SSLMode
}
case "sqlserver":
dsn = fmt.Sprintf("server=%s;port=%d;database=%s;user id=%s;password=%s",
config.Host, config.Port, config.Database, config.Username, config.Password)
default:
return nil, fmt.Errorf("unsupported database type: %s", config.Type)
}
db, err := sql.Open(config.Type, dsn)
if err != nil {
return nil, fmt.Errorf("failed to open database: %v", err)
}
// 测试连接
if err := db.Ping(); err != nil {
return nil, fmt.Errorf("failed to ping database: %v", err)
}
// 设置连接池参数
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(5 * time.Minute)
dm := &DatabaseManager{
db: db,
config: config,
}
// 初始化数据库表
if err := dm.initTables(); err != nil {
return nil, fmt.Errorf("failed to initialize tables: %v", err)
}
return dm, nil
}
// initTables 初始化数据库表
func (dm *DatabaseManager) initTables() error {
var createTableSQL string
switch dm.config.Type {
case "mysql":
createTableSQL = `
CREATE TABLE IF NOT EXISTS cameras (
id VARCHAR(36) PRIMARY KEY,
name VARCHAR(255) NOT NULL,
ip VARCHAR(45) NOT NULL,
username VARCHAR(100),
password VARCHAR(100),
rtsp_url TEXT NOT NULL,
enabled BOOLEAN DEFAULT TRUE,
on_demand BOOLEAN DEFAULT FALSE,
audio BOOLEAN DEFAULT TRUE,
debug BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_enabled (enabled),
INDEX idx_ip (ip)
)`
case "sqlserver":
createTableSQL = `
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='cameras' AND xtype='U')
CREATE TABLE cameras (
id NVARCHAR(36) PRIMARY KEY,
name NVARCHAR(255) NOT NULL,
ip NVARCHAR(45) NOT NULL,
username NVARCHAR(100),
password NVARCHAR(100),
rtsp_url NTEXT NOT NULL,
enabled BIT DEFAULT 1,
on_demand BIT DEFAULT 0,
audio BIT DEFAULT 1,
debug BIT DEFAULT 0,
created_at DATETIME2 DEFAULT GETDATE(),
updated_at DATETIME2 DEFAULT GETDATE()
)`
}
_, err := dm.db.Exec(createTableSQL)
return err
}
// GetAllCameras 获取所有摄像头
func (dm *DatabaseManager) GetAllCameras() ([]Camera, error) {
query := `SELECT id, name, ip, username, password, rtsp_url, enabled, on_demand, audio, debug, created_at, updated_at FROM cameras WHERE enabled = ?`
rows, err := dm.db.Query(query, true)
if err != nil {
return nil, err
}
defer rows.Close()
var cameras []Camera
for rows.Next() {
var camera Camera
err := rows.Scan(&camera.ID, &camera.Name, &camera.IP, &camera.Username,
&camera.Password, &camera.RTSPURL, &camera.Enabled, &camera.OnDemand,
&camera.Audio, &camera.Debug, &camera.CreatedAt, &camera.UpdatedAt)
if err != nil {
return nil, err
}
cameras = append(cameras, camera)
}
return cameras, nil
}
// GetCameraByID 根据ID获取摄像头
func (dm *DatabaseManager) GetCameraByID(id string) (*Camera, error) {
query := `SELECT id, name, ip, username, password, rtsp_url, enabled, on_demand, audio, debug, created_at, updated_at FROM cameras WHERE id = ?`
var camera Camera
err := dm.db.QueryRow(query, id).Scan(&camera.ID, &camera.Name, &camera.IP,
&camera.Username, &camera.Password, &camera.RTSPURL, &camera.Enabled,
&camera.OnDemand, &camera.Audio, &camera.Debug, &camera.CreatedAt, &camera.UpdatedAt)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
return nil, err
}
return &camera, nil
}
// CreateCamera 创建摄像头
func (dm *DatabaseManager) CreateCamera(camera *Camera) error {
if camera.ID == "" {
camera.ID = uuid.New().String()
}
camera.CreatedAt = time.Now()
camera.UpdatedAt = time.Now()
query := `INSERT INTO cameras (id, name, ip, username, password, rtsp_url, enabled, on_demand, audio, debug, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
_, err := dm.db.Exec(query, camera.ID, camera.Name, camera.IP, camera.Username,
camera.Password, camera.RTSPURL, camera.Enabled, camera.OnDemand,
camera.Audio, camera.Debug, camera.CreatedAt, camera.UpdatedAt)
return err
}
// UpdateCamera 更新摄像头
func (dm *DatabaseManager) UpdateCamera(camera *Camera) error {
camera.UpdatedAt = time.Now()
query := `UPDATE cameras SET name=?, ip=?, username=?, password=?, rtsp_url=?,
enabled=?, on_demand=?, audio=?, debug=?, updated_at=? WHERE id=?`
_, err := dm.db.Exec(query, camera.Name, camera.IP, camera.Username,
camera.Password, camera.RTSPURL, camera.Enabled, camera.OnDemand,
camera.Audio, camera.Debug, camera.UpdatedAt, camera.ID)
return err
}
// DeleteCamera 删除摄像头
func (dm *DatabaseManager) DeleteCamera(id string) error {
query := `DELETE FROM cameras WHERE id = ?`
_, err := dm.db.Exec(query, id)
return err
}
// Close 关闭数据库连接
func (dm *DatabaseManager) Close() error {
if dm.db != nil {
return dm.db.Close()
}
return nil
}
// CameraToStream 将摄像头转换为流配置
func CameraToStream(camera Camera) StreamST {
return StreamST{
Name: camera.Name,
Channels: map[string]ChannelST{
"0": {
Name: camera.Name,
URL: camera.RTSPURL,
OnDemand: camera.OnDemand,
Debug: camera.Debug,
Audio: camera.Audio,
},
},
}
}
// StreamToCamera 将流配置转换为摄像头
func StreamToCamera(id string, stream StreamST) Camera {
camera := Camera{
ID: id,
Name: stream.Name,
Enabled: true,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
// 获取第一个通道的配置
if len(stream.Channels) > 0 {
for _, channel := range stream.Channels {
camera.RTSPURL = channel.URL
camera.OnDemand = channel.OnDemand
camera.Debug = channel.Debug
camera.Audio = channel.Audio
break
}
}
return camera
}