添加用户及设备信息数据库查询,添加wss获取视频图片帧

This commit is contained in:
lijun 2025-01-14 15:00:40 +08:00
parent fab3bb77c6
commit 85fd2567d5
10 changed files with 430 additions and 6 deletions

49
dao/db.go Normal file
View File

@ -0,0 +1,49 @@
package dao
import (
"VideoStream/proto"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
var DB *gorm.DB
func Init() error {
var db *gorm.DB
var err error
var dsn string
if proto.Config.DB == 0 {
dsn = proto.Config.MYSQL_DSN
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
} else if proto.Config.DB == 1 {
dsn = proto.Config.PG_DSN
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
}
if err != nil {
panic("failed to connect database")
return err
}
err = db.AutoMigrate(&User{})
if err != nil {
fmt.Println("user table:", err)
return err
} // 自动迁移,创建表,如果表已经存在,会自动更新表结构,不会删除表,只会创建不存在的表
err = db.AutoMigrate(&Device{})
if err != nil {
fmt.Println("device table:", err)
return err
} // 自动迁移,创建表,如果表已经存在,会自动更新表结构,不会删除表,只会创建不存在的表
DB = db
return err
}
func Close() {
sqlDB, err := DB.DB()
if err != nil {
panic("failed to connect database")
}
sqlDB.Close()
}

22
dao/device.go Normal file
View File

@ -0,0 +1,22 @@
package dao
import (
"gorm.io/gorm"
)
type Device struct {
gorm.Model
AuthID int `gorm:"column:auth_id"`
DeviceName string `gorm:"column:device_name"`
DeviceType string `gorm:"column:device_type"`
DeviceStatus string `gorm:"column:device_status"`
DeviceLocation string `gorm:"column:device_location"`
DeviceIP string `gorm:"column:device_ip"`
DeviceInfo string `gorm:"column:device_info"`
}
func FindDeviceByID(id, auth_id int) Device {
var device Device
DB.Where("id = ? and auth_id = ?", id, auth_id).First(&device)
return device
}

34
dao/user.go Normal file
View File

@ -0,0 +1,34 @@
package dao
import "gorm.io/gorm"
type User struct {
gorm.Model
Name string `gorm:"column:name"`
Age int `gorm:"column:age"`
Email string `gorm:"column:email"`
Password string `gorm:"column:password"`
Gender string `gorm:"column:gender"`
Role string `gorm:"column:role"`
Redis bool `gorm:"column:redis"`
Run bool `gorm:"column:run"`
Upload bool `gorm:"column:upload"`
VideoFunc bool `gorm:"column:video_func"` //视频功能
DeviceFunc bool `gorm:"column:device_func"` //设备功能
CIDFunc bool `gorm:"column:cid_func"` //持续集成功能
Avatar string `gorm:"column:avatar"`
CreateTime string `gorm:"column:create_time"`
UpdateTime string `gorm:"column:update_time"`
}
func FindUserByID(id int) []User {
var users []User
DB.Where("id = ?", id).First(&users)
return users
}
func FindUserByID2(id int) User {
var user User
DB.Where("id = ?", id).First(&user)
return user
}

22
go.mod
View File

@ -1,12 +1,20 @@
module VideoStream
go 1.21
go 1.22
toolchain go1.22.10
require (
github.com/gin-gonic/gin v1.10.0
github.com/go-redis/redis/v8 v8.11.5
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.3
github.com/robfig/cron/v3 v3.0.1
gocv.io/x/gocv v0.39.0
gorm.io/driver/mysql v1.5.7
gorm.io/driver/postgres v1.5.11
gorm.io/gorm v1.25.12
)
require (
@ -21,20 +29,30 @@ require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.5.5 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/text v0.15.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

43
go.sum
View File

@ -8,6 +8,7 @@ github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -31,17 +32,41 @@ github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBEx
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@ -63,6 +88,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@ -88,18 +115,21 @@ golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
@ -107,5 +137,12 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314=
gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

View File

@ -3,16 +3,59 @@ package handler
import (
"VideoStream/proto"
"VideoStream/service"
"VideoStream/worker"
"fmt"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/gorilla/websocket"
"gocv.io/x/gocv"
"io"
"net/http"
"strconv"
"time"
)
var (
upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
// 允许所有来源的连接
return true
},
}
)
func SetUpToolGroup(router *gin.Engine) {
toolGroup := router.Group("/tool")
toolGroup.GET("/video_stream", GetVideoStream)
toolGroup.GET("/video_real_time", GetRealTimeImage)
}
// 跨域访问cross origin resource share
func CrosHandler() gin.HandlerFunc {
return func(context *gin.Context) {
//method := context.Request.Method
context.Writer.Header().Set("Access-Control-Allow-Origin", "*")
context.Header("Access-Control-Allow-Origin", "*") // 设置允许访问所有域
context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
context.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma,token,openid,opentoken")
context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")
context.Header("Access-Control-Max-Age", "172800")
context.Header("Access-Control-Allow-Credentials", "false")
context.Set("content-type", "application/json") //设置返回格式是json
// if method == "OPTIONS" {
// context.JSON(http.StatusOK, gin.H{
// "code":1,
// "message":"error",
// "data":"request error",
// })
// }
//处理请求
context.Next()
}
}
type videoStreamReq struct {
@ -77,3 +120,72 @@ func GetVideoStream(c *gin.Context) {
}
}
// 发送实时视频流
func GetRealTimeImage(c *gin.Context) {
id, _ := c.Get("id")
id1 := id.(int)
device_id := c.Query("device_id")
device_id_int, _ := strconv.Atoi(device_id)
device := service.GetDevice(device_id_int, id1)
if device.ID == 0 {
c.JSON(http.StatusOK, gin.H{"code": 4, "message": "device not found"})
return
}
ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
fmt.Println("connect wss err:", err)
return
}
worker.SetRedisWithExpire(strconv.Itoa(int(device.ID))+"_is_play", "1", time.Minute*5)
fmt.Println("device_id:", device_id_int, " has set is_play to 1")
go subscribeAndHandleMessagesV3(ws, device_id_int)
}
func subscribeAndHandleMessagesV3(ws *websocket.Conn, device_id int) {
// 生成唯一连接 uuid
con_id := uuid.New().String()
online_conn_key := "device_" + strconv.Itoa(device_id) + "_online_conn_ids"
// 加入设备在线连接集合
worker.SetRedisSetAddWithExpire(online_conn_key, con_id, time.Minute*5)
//图片计数器
count := 0
//定时器,发送计数器
t_count := 0
for {
//从service获取当前帧
img, c := service.GetDeviceCurrentFrame(device_id)
if c != count {
//将img转[]byte
buf, _ := gocv.IMEncode(".jpg", img)
buf1 := buf.GetBytes()
err2 := ws.WriteMessage(websocket.BinaryMessage, buf1)
if err2 != nil {
fmt.Println("send message to client err:", err2)
worker.SetRedisSetRemove(online_conn_key, con_id)
goto end
}
c = count
} else {
//每秒发送一次心跳检测
if t_count%10 == 0 {
err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(time.Second))
if err != nil {
fmt.Println("Connection check failed:", err)
worker.SetRedisSetRemove(online_conn_key, con_id)
goto end
}
}
}
time.Sleep(100 * time.Millisecond)
t_count++
}
end:
// 查看是否还有其他连接,没有则设置 is_play 为 0
if worker.IsContainKey(online_conn_key) == false {
worker.SetRedisWithExpire(strconv.Itoa(device_id)+"_is_play", "1", time.Minute*5)
fmt.Println("device_id:", device_id, " has set is_play to 0")
}
}

98
main.go
View File

@ -1,21 +1,37 @@
package main
import (
"VideoStream/dao"
"VideoStream/handler"
"VideoStream/proto"
"VideoStream/service"
"VideoStream/worker"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt"
"github.com/robfig/cron/v3"
"gocv.io/x/gocv"
"log"
"strconv"
"strings"
"sync"
)
func main() {
gin.SetMode(gin.ReleaseMode)
r := gin.Default()
handler.SetUpToolGroup(r) // Tool
err0 := dao.Init()
defer dao.Close()
if err0 != nil {
panic("failed to connect database:" + err0.Error())
}
err0 = worker.InitRedis()
defer worker.CloseRedis()
if err0 != nil {
panic("failed to connect redis:" + err0.Error())
}
r.Use(handler.CrosHandler())
r.Use(JWTAuthMiddleware()) // 使用 JWT 认证中间件
handler.SetUpToolGroup(r) // Tool
err := worker.InitRedis()
if err != nil {
panic("failed to connect redis:" + err.Error())
@ -69,3 +85,83 @@ func ReadConfigAndSetSystem() {
}
}
}
func JWTAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 从请求头中获取 JWT 令牌
tokenString := c.Request.Header.Get("token")
//请求方式为get时从url中获取token
if tokenString == "" {
tokenString = c.Query("token")
}
//如果请求为login或register则不需要验证token
for k, _ := range proto.Url_map {
if strings.Contains(c.Request.URL.Path, k) {
c.Next()
return
}
}
if tokenString == "" {
//c.AbortWithStatus(200)
c.JSON(200, gin.H{
"message": "Unauthorized",
"error": "token is empty",
"code": 3,
})
return
}
if proto.Config.TOKEN_USE_REDIS {
redisToken := worker.GetRedis(tokenString)
if redisToken == "" {
c.AbortWithStatus(200)
c.JSON(200, gin.H{
"message": "NOT_LOGIN",
"error": "server token is empty",
"code": 3,
})
return
}
}
//查看token是否在超级token中
if worker.IsContainSet("super_permission_tokens", tokenString) {
s_id := c.Request.Header.Get("super_id")
if s_id == "" {
c.AbortWithStatus(200)
c.JSON(200, gin.H{
"message": "NOT_LOGIN",
"error": "super_id is empty",
"code": 3,
})
return
}
id, _ := strconv.Atoi(s_id)
//查看s_id类型
c.Set("id", id)
c.Next()
return
}
// 使用加密secret 解析 JWT 令牌
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return proto.SigningKey, nil
})
// 验证令牌
if err != nil || !token.Valid {
c.AbortWithStatus(200)
c.JSON(200, gin.H{
"message": "NOT_LOGIN",
"error": "Invalid token",
"code": 4,
})
return
}
userId := int(token.Claims.(jwt.MapClaims)["id"].(float64))
// 将用户信息添加到上下文中
c.Set("id", userId)
// 继续处理请求
c.Next()
}
}

View File

@ -7,8 +7,14 @@ import (
)
var Config ConfigStruct
var Url_map = map[string]bool{} // 不需要token验证的url
var SigningKey = []byte{}
type ConfigStruct struct {
DB int `json:"db"` // 0: mysql, 1: pg
MYSQL_DSN string `json:"mysql_dsn"`
PG_DSN string `json:"pg_dsn"`
TOKEN_SECRET string `json:"token_secret"`
REDIS_ADDR string `json:"redis_addr"`
TOKEN_USE_REDIS bool `json:"token_use_redis"`
REDIS_User_PW bool `json:"redis_user_pw"` // 是否使用密码
@ -68,5 +74,9 @@ func ReadConfig(path string) error {
Config.SERVER_PORT = "5002" // 默认端口
}
}
SigningKey = []byte(Config.TOKEN_SECRET)
if Config.TOKEN_SECRET == "" {
err = fmt.Errorf("token secret is empty")
}
return err
}

View File

@ -1,6 +1,7 @@
package service
import (
"VideoStream/dao"
"VideoStream/proto"
"fmt"
"gocv.io/x/gocv"
@ -141,3 +142,7 @@ func DoGetVideoStream() {
go GetVideoStream(device.ID)
}
}
func GetDevice(id, auth_id int) dao.Device {
return dao.FindDeviceByID(id, auth_id)
}

41
service/user.go Normal file
View File

@ -0,0 +1,41 @@
package service
import (
"VideoStream/dao"
"VideoStream/worker"
"encoding/json"
"fmt"
"strconv"
)
// 获取用户信息有redis缓存
func GetUserByIDWithCache(id int) dao.User {
if id <= 0 {
return dao.User{}
}
var user dao.User
//先从redis获取
key := "user_info_" + strconv.Itoa(id)
user_str := worker.GetRedis(key)
if user_str != "" {
err := json.Unmarshal([]byte(user_str), &user)
if err != nil {
fmt.Println("get user info , json unmarshal error:", err, "\tuser_str:", user_str)
return dao.User{}
}
} else {
user = dao.FindUserByID2(id)
if user.ID != 0 {
userJson, err := json.Marshal(user)
if err != nil {
fmt.Println("get user info , json marshal error:", err)
return dao.User{}
}
success := worker.SetRedis(key, string(userJson))
if !success {
fmt.Println("set redis error,user json:", string(userJson))
}
}
}
return user
}