Compare commits
196 Commits
9755d73b86
...
a9a9ecc3bd
| Author | SHA1 | Date |
|---|---|---|
|
|
a9a9ecc3bd | |
|
|
a2441cdc20 | |
|
|
7cc505daec | |
|
|
aeacecea70 | |
|
|
e94695329c | |
|
|
3967d68ce0 | |
|
|
510b725ade | |
|
|
ef1b2771cd | |
|
|
cf404a97b9 | |
|
|
ab2f5fd1b7 | |
|
|
d6bf91c9fd | |
|
|
892e080d6a | |
|
|
abd00e9ec0 | |
|
|
6366a02900 | |
|
|
1dd87d717e | |
|
|
4ecdda9468 | |
|
|
8a55bfc82b | |
|
|
724c5e6c1f | |
|
|
252fa4683b | |
|
|
aa4b2a8f10 | |
|
|
770a9df5d7 | |
|
|
9cf9876fb9 | |
|
|
395f1f681d | |
|
|
0fc72a86d6 | |
|
|
cc21f69fc0 | |
|
|
16014ff420 | |
|
|
7672b3a638 | |
|
|
963790ed47 | |
|
|
bdc32ec806 | |
|
|
6c57f60170 | |
|
|
40a119cebb | |
|
|
269e8d70f1 | |
|
|
ad24877771 | |
|
|
29f1354cdd | |
|
|
a164def0cd | |
|
|
757062b65f | |
|
|
1bed10c5e5 | |
|
|
8c3db1ce1d | |
|
|
793d306238 | |
|
|
66bd811f05 | |
|
|
7581a17a29 | |
|
|
7c4b0d4649 | |
|
|
af83caeaa4 | |
|
|
41eb5c6367 | |
|
|
ccf1916e4e | |
|
|
8e20f59d01 | |
|
|
b75d6a62ef | |
|
|
e45d802ec8 | |
|
|
2042c11b40 | |
|
|
88ab3a6614 | |
|
|
0ebc447c32 | |
|
|
a6954f8f9e | |
|
|
bda9e235de | |
|
|
e1b2361ef0 | |
|
|
ac3f88c8ce | |
|
|
e9fd3b346d | |
|
|
32bf491219 | |
|
|
5bbb158a7d | |
|
|
e6c51f423c | |
|
|
8165233396 | |
|
|
ecb5656a92 | |
|
|
7e1d876604 | |
|
|
04a01ddb32 | |
|
|
a3e32c3755 | |
|
|
484ee75736 | |
|
|
ab05433289 | |
|
|
4270e77780 | |
|
|
f92fd4767c | |
|
|
038ce10c19 | |
|
|
92afee454c | |
|
|
288f5a0db6 | |
|
|
369264e695 | |
|
|
e34d29b0a4 | |
|
|
7baaa5453a | |
|
|
d618cf0332 | |
|
|
5a3f899772 | |
|
|
f1695df463 | |
|
|
e1ae537386 | |
|
|
5f98ed5651 | |
|
|
f22df7f012 | |
|
|
2320a997b4 | |
|
|
3b46273a3b | |
|
|
1c232b0b83 | |
|
|
5dcd98ab3a | |
|
|
af18019ac3 | |
|
|
8d9a953c53 | |
|
|
6880e033a8 | |
|
|
a83aa1002d | |
|
|
d601fcd210 | |
|
|
2d155b3156 | |
|
|
80cafbc839 | |
|
|
aac77e078a | |
|
|
fc915a0f7c | |
|
|
c9620b64dc | |
|
|
7a650394b0 | |
|
|
381fd3d720 | |
|
|
16885ee880 | |
|
|
928e7f9799 | |
|
|
11f5b02559 | |
|
|
46ad8baa3b | |
|
|
3477c7fad4 | |
|
|
a10d4add52 | |
|
|
09f1a3e38d | |
|
|
b919c068ba | |
|
|
a92a9b97f0 | |
|
|
31d28cbff2 | |
|
|
83282285cb | |
|
|
54f8b03159 | |
|
|
f092e3ac4d | |
|
|
bc1e89280e | |
|
|
2345387422 | |
|
|
8214806a2f | |
|
|
68d9082f96 | |
|
|
586356c18a | |
|
|
0f37e738a7 | |
|
|
d9edd7fa7a | |
|
|
8689f78181 | |
|
|
edef1fd7e0 | |
|
|
ec0c152032 | |
|
|
536b9eb29a | |
|
|
119420932b | |
|
|
fdc3674ff5 | |
|
|
a6ce904059 | |
|
|
3ab7556b38 | |
|
|
c5258b3fb2 | |
|
|
db73c16fe3 | |
|
|
c65ff352df | |
|
|
3e8a2938c0 | |
|
|
766dbcd2fb | |
|
|
a3916a77d0 | |
|
|
945591f695 | |
|
|
f428c0a758 | |
|
|
be079f9b31 | |
|
|
909bf31192 | |
|
|
31ef5ee93b | |
|
|
39cb9bc91f | |
|
|
a803991a42 | |
|
|
aa765e9412 | |
|
|
fb3d2e8e67 | |
|
|
4128347eab | |
|
|
e9f089c6a2 | |
|
|
7b93f3a801 | |
|
|
d8967012d3 | |
|
|
de6b65022a | |
|
|
a28b830523 | |
|
|
d62ef9710d | |
|
|
3e68e4cfa8 | |
|
|
5356efaa73 | |
|
|
9c9a6bf870 | |
|
|
9408bc3831 | |
|
|
ed7e5e68ef | |
|
|
9fed2927fc | |
|
|
47df437cdd | |
|
|
a9c57ef016 | |
|
|
366e9f2821 | |
|
|
e441b554e8 | |
|
|
d0619ca01b | |
|
|
dfe767834b | |
|
|
fff1d93848 | |
|
|
664027a955 | |
|
|
3238116f37 | |
|
|
9d01e83d71 | |
|
|
27858d41e7 | |
|
|
ac8b347cc2 | |
|
|
6560a9a5c2 | |
|
|
b5cd667088 | |
|
|
645106e3e6 | |
|
|
2f0266f3ee | |
|
|
f421dda674 | |
|
|
8e91296373 | |
|
|
05489c8fd7 | |
|
|
067c4ccfe2 | |
|
|
4c9616202d | |
|
|
203559ed82 | |
|
|
61a94ec047 | |
|
|
36b0862db7 | |
|
|
8187c36585 | |
|
|
80602dd4c4 | |
|
|
c5dcd895f4 | |
|
|
e9a95012bd | |
|
|
a05d3b3c7f | |
|
|
f10e46761b | |
|
|
a621cb5ad2 | |
|
|
f720eb509b | |
|
|
1bb639504d | |
|
|
64069034db | |
|
|
eb7a57c215 | |
|
|
62d336e1c0 | |
|
|
71783fe15f | |
|
|
3571772bb1 | |
|
|
8796ef784b | |
|
|
f60328be98 | |
|
|
1b9cf8b3d3 | |
|
|
29e8151420 | |
|
|
4918c54fc6 | |
|
|
65f98fe9de |
15
dao/cid.go
15
dao/cid.go
|
|
@ -17,11 +17,12 @@ type CID struct {
|
||||||
|
|
||||||
type CIDRunLog struct {
|
type CIDRunLog struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
CID_id int `gorm:"column:cid_id"`
|
CID_id int `gorm:"column:cid_id"`
|
||||||
Auth_id int `form:"column:auth_id"`
|
Auth_id int `form:"column:auth_id"`
|
||||||
Script string `gorm:"column:script"`
|
Script string `gorm:"column:script"`
|
||||||
Log string `gorm:"column:log"`
|
RunTime float64 `gorm:"column:run_time"`
|
||||||
Error string `gorm:"column:error"`
|
Log string `gorm:"column:log"`
|
||||||
|
Error string `gorm:"column:error"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateCID 创建持续集成、部署
|
// CreateCID 创建持续集成、部署
|
||||||
|
|
@ -75,8 +76,8 @@ func UpdateCIDByID(id, auth_id, time int, name, url, script, token string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateRunLog,添加执行日志
|
// CreateRunLog,添加执行日志
|
||||||
func CreateRunLog(cid_id, auth_id int, script, log, err string) uint {
|
func CreateRunLog(cid_id, auth_id int, script, log, err string, runtime float64) uint {
|
||||||
cidRunLog := CIDRunLog{CID_id: cid_id, Auth_id: auth_id, Log: log, Error: err, Script: script}
|
cidRunLog := CIDRunLog{CID_id: cid_id, Auth_id: auth_id, Log: log, Error: err, Script: script, RunTime: runtime}
|
||||||
result := DB.Create(&cidRunLog)
|
result := DB.Create(&cidRunLog)
|
||||||
if result != nil {
|
if result != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
|
|
||||||
23
dao/db.go
23
dao/db.go
|
|
@ -76,11 +76,34 @@ func Init() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = db.AutoMigrate(&File{})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("file table:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.AutoMigrate(&ConfigFile{})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("config file table:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.AutoMigrate(&FileAuth{})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("file auth table:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
err = db.AutoMigrate(&Friend{})
|
err = db.AutoMigrate(&Friend{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("friend table:", err)
|
fmt.Println("friend table:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = db.AutoMigrate(&Shell{})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("shell table:", err)
|
||||||
|
}
|
||||||
|
|
||||||
DB = db
|
DB = db
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
114
dao/file.go
114
dao/file.go
|
|
@ -1,25 +1,47 @@
|
||||||
package dao
|
package dao
|
||||||
|
|
||||||
import "gorm.io/gorm"
|
import (
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"videoplayer/proto"
|
||||||
|
)
|
||||||
|
|
||||||
type File struct {
|
type File struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
// 存储文件名
|
// 存储文件名
|
||||||
FileStoreName string `gorm:"column:file_store_name;uniqueIndex:idx_file_name"`
|
FileStoreName string `gorm:"column:file_store_name;type:varchar(255);uniqueIndex:idx_file_name"`
|
||||||
|
NeedAuth bool `gorm:"column:need_auth"`
|
||||||
FileName string `gorm:"column:file_name"`
|
FileName string `gorm:"column:file_name"`
|
||||||
FileSize int `gorm:"column:file_size"`
|
FileSize int `gorm:"column:file_size"`
|
||||||
FileType string `gorm:"column:file_type"`
|
FileType string `gorm:"column:file_type"`
|
||||||
FilePath string `gorm:"column:file_path"`
|
FilePath string `gorm:"column:file_path"`
|
||||||
AuthID int `gorm:"column:auth_id"`
|
AuthID int `gorm:"column:auth_id"`
|
||||||
|
Md5 string `gorm:"column:md5;type:varchar(255);uniqueIndex:idx_file_name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateFile(fileStoreName, fileName, fileType, filePath string, fileSize, authID int) uint {
|
type FileAuth struct {
|
||||||
file := File{FileStoreName: fileStoreName, FileName: fileName, FileType: fileType, FilePath: filePath, FileSize: fileSize, AuthID: authID}
|
gorm.Model
|
||||||
|
AuthID int `gorm:"column:auth_id"`
|
||||||
|
FileID int `gorm:"column:file_id"`
|
||||||
|
UserFileName string `gorm:"column:user_file_name;type:varchar(255);uniqueIndex:idx_file_name"` //对于同一个文件,不同用户有不同的文件名
|
||||||
|
UploadType string `gorm:"column:upload_type"` // 上传类型: im,avatar,file,config,config为系统文件
|
||||||
|
IsPrivate int `gorm:"column:is_private"` // 是否私有,私有文件只能自己下载或者通过分享链接下载,1为私有,0为公开
|
||||||
|
ShareCode string `gorm:"column:share_code"` // 分享码,用于分享时的验证,构建分享链接
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigFile struct {
|
||||||
|
gorm.Model
|
||||||
|
AuthID int `gorm:"column:auth_id"`
|
||||||
|
FileName string `gorm:"column:file_name"`
|
||||||
|
FilePath string `gorm:"column:file_path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateFile(fileStoreName, fileName, fileType, filePath, md5Str string, fileSize, authID int, NeedAuth bool) File {
|
||||||
|
file := File{FileStoreName: fileStoreName, FileName: fileName, FileType: fileType, FilePath: filePath, FileSize: fileSize, AuthID: authID, NeedAuth: NeedAuth, Md5: md5Str}
|
||||||
result := DB.Create(&file)
|
result := DB.Create(&file)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return 0
|
return File{}
|
||||||
}
|
}
|
||||||
return file.ID
|
return file
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteFileByID(id, user int) bool {
|
func DeleteFileByID(id, user int) bool {
|
||||||
|
|
@ -42,6 +64,12 @@ func FindFileByNames(fileName string, auth_id int) File {
|
||||||
return file
|
return file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FindFileByName(fileName string) File {
|
||||||
|
var file File
|
||||||
|
DB.Where("file_store_name = ?", fileName).First(&file)
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
func FindFileByAuthID(auth_id int) []File {
|
func FindFileByAuthID(auth_id int) []File {
|
||||||
var files []File
|
var files []File
|
||||||
DB.Where("auth_id = ?", auth_id).Find(&files)
|
DB.Where("auth_id = ?", auth_id).Find(&files)
|
||||||
|
|
@ -75,3 +103,77 @@ func DeleteFileById(id int) bool {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FindFileByMd5(md5 string) File {
|
||||||
|
var file File
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
DB.Debug().Where("md5 = ?", md5).First(&file)
|
||||||
|
} else {
|
||||||
|
DB.Where("md5 = ?", md5).First(&file)
|
||||||
|
}
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateFileAuth(authID, fileID int, userFileName, uploadType string, isPrivate int, shareCode string) FileAuth {
|
||||||
|
fileAuth := FileAuth{AuthID: authID, FileID: fileID, UserFileName: userFileName, UploadType: uploadType, IsPrivate: isPrivate, ShareCode: shareCode}
|
||||||
|
var result *gorm.DB
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
result = DB.Debug().Create(&fileAuth)
|
||||||
|
} else {
|
||||||
|
result = DB.Create(&fileAuth)
|
||||||
|
}
|
||||||
|
if result.Error != nil {
|
||||||
|
return FileAuth{}
|
||||||
|
}
|
||||||
|
return fileAuth
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateConfigFile(file ConfigFile) (id uint, err error) {
|
||||||
|
var result *gorm.DB
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
result = DB.Debug().Create(&file)
|
||||||
|
} else {
|
||||||
|
result = DB.Create(&file)
|
||||||
|
}
|
||||||
|
return file.ID, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindConfigFileByID(id int, user_id int) ConfigFile {
|
||||||
|
var file ConfigFile
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
DB.Debug().Where("id = ? and auth_id = ?", id, user_id).First(&file)
|
||||||
|
} else {
|
||||||
|
DB.Where("id = ? and auth_id = ?", id, user_id).First(&file)
|
||||||
|
}
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteConfigFileByID(id int) error {
|
||||||
|
var res *gorm.DB
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
res = DB.Debug().Delete(&ConfigFile{}, id)
|
||||||
|
} else {
|
||||||
|
res = DB.Delete(&ConfigFile{}, id)
|
||||||
|
}
|
||||||
|
return res.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateConfigFileByID(id int, file ConfigFile) error {
|
||||||
|
var res *gorm.DB
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
res = DB.Debug().Model(&ConfigFile{}).Where("id = ?", id).Updates(&file)
|
||||||
|
} else {
|
||||||
|
res = DB.Model(&ConfigFile{}).Where("id = ?", id).Updates(&file)
|
||||||
|
}
|
||||||
|
return res.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindConfigFileByAuthID(auth_id int) []ConfigFile {
|
||||||
|
var files []ConfigFile
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
DB.Debug().Where("auth_id = ?", auth_id).Find(&files)
|
||||||
|
} else {
|
||||||
|
DB.Where("auth_id = ?", auth_id).Find(&files)
|
||||||
|
}
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -231,9 +231,10 @@ func FindFriend(from_user_id, to_user_id int) []Friend {
|
||||||
}
|
}
|
||||||
|
|
||||||
type FriendRet struct {
|
type FriendRet struct {
|
||||||
ID int `json:"id"` //用户id
|
ID int `json:"id"` //用户id
|
||||||
Name string `json:"name"` //用户名
|
Name string `json:"name"` //用户名
|
||||||
Email string `json:"email"` //邮箱
|
Email string `json:"email"` //邮箱
|
||||||
|
Avatar string `json:"avatar"` //头像
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindFriendsIDs(user_id int) []Friend {
|
func FindFriendsIDs(user_id int) []Friend {
|
||||||
|
|
@ -244,7 +245,7 @@ func FindFriendsIDs(user_id int) []Friend {
|
||||||
|
|
||||||
func FindFriends(user_id int) []FriendRet {
|
func FindFriends(user_id int) []FriendRet {
|
||||||
var friends []FriendRet
|
var friends []FriendRet
|
||||||
DB.Raw("select distinct users.id, users.name, users.email from users join friends on users.id = friends.friend_id where friends.user_id = ? and friends.deleted_at is null", user_id).Scan(&friends)
|
DB.Raw("select distinct users.id, users.name, users.email,users.avatar from users join friends on users.id = friends.friend_id where friends.user_id = ? and friends.deleted_at is null", user_id).Scan(&friends)
|
||||||
return friends
|
return friends
|
||||||
}
|
}
|
||||||
func GetGroups(user_id int) []Group {
|
func GetGroups(user_id int) []Group {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"log"
|
||||||
|
"videoplayer/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Shell struct {
|
||||||
|
gorm.Model
|
||||||
|
AuthID uint `gorm:"column:auth_id"`
|
||||||
|
Server string `gorm:"column:server"`
|
||||||
|
ShellName string `gorm:"column:shell_name"`
|
||||||
|
ShellContent string `gorm:"column:shell_content"`
|
||||||
|
Status int `gorm:"column:status"` // 0 未执行 1 执行中 2 执行完成
|
||||||
|
ShellResult string `gorm:"column:shell_result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateShell(shellName, shellContent, server string, uid uint) uint {
|
||||||
|
shell := Shell{ShellName: shellName, ShellContent: shellContent, Server: server, AuthID: uid}
|
||||||
|
var res *gorm.DB
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
res = DB.Debug().Create(&shell)
|
||||||
|
} else {
|
||||||
|
res = DB.Create(&shell)
|
||||||
|
}
|
||||||
|
if res.Error != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return shell.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindShellByID(id, uid uint) []Shell {
|
||||||
|
var shell Shell
|
||||||
|
var result *gorm.DB
|
||||||
|
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
result = DB.Debug().Where("id = ? and auth_id = ?", id, uid).First(&shell)
|
||||||
|
} else {
|
||||||
|
result = DB.Where("id = ? and auth_id = ?", id, uid).First(&shell)
|
||||||
|
}
|
||||||
|
var res []Shell
|
||||||
|
res = append(res, shell)
|
||||||
|
if result.Error != nil {
|
||||||
|
log.Printf("FindShellByID failed: %v", result.Error)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindShellByAuthID(auth_id int) []Shell {
|
||||||
|
var shells []Shell
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
DB.Debug().Where("auth_id = ?", auth_id).Order("created_at DESC").Limit(100).Find(&shells)
|
||||||
|
} else {
|
||||||
|
DB.Where("auth_id = ?", auth_id).Order("created_at DESC").Limit(100).Find(&shells)
|
||||||
|
}
|
||||||
|
return shells
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateShellByID(id, authId uint, shellName, shellContent string, status int, shellResult string) bool {
|
||||||
|
pd := FindShellByID(id, authId)
|
||||||
|
if pd[0].ID == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var result *gorm.DB
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
result = DB.Debug().Model(&Shell{}).Where("id = ? and auth_id = ?", id, authId).Updates(Shell{ShellName: shellName, ShellContent: shellContent, Status: status, ShellResult: shellResult})
|
||||||
|
} else {
|
||||||
|
result = DB.Model(&Shell{}).Where("id = ? and auth_id = ?", id, authId).Updates(Shell{ShellName: shellName, ShellContent: shellContent, Status: status, ShellResult: shellResult})
|
||||||
|
}
|
||||||
|
if result.Error != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindShellWillRunByServer(server string, uid uint) []Shell {
|
||||||
|
var shells []Shell
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
result := DB.Debug().Where("server = ? AND auth_id = ? AND status = 0", server, uid).
|
||||||
|
Order("created_at DESC").
|
||||||
|
Limit(100).
|
||||||
|
Find(&shells)
|
||||||
|
if result.Error != nil {
|
||||||
|
// 若查询过程中出现错误,输出错误信息
|
||||||
|
log.Printf("Failed to query shells: %v\n", result.Error)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//DB.Exec("select * from shells where server = ? and auth_id = ? and status = 0 order by created_at desc limit 100", server, uid).Scan(&shells)
|
||||||
|
result := DB.Where("server = ? AND auth_id = ? AND status = 0", server, uid).
|
||||||
|
Order("created_at DESC").
|
||||||
|
Limit(100).
|
||||||
|
Find(&shells)
|
||||||
|
if result.Error != nil {
|
||||||
|
// 若查询过程中出现错误,输出错误信息
|
||||||
|
log.Printf("Failed to query shells: %v\n", result.Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shells
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteShellByID(id, authId uint) bool {
|
||||||
|
var db2 *gorm.DB
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
db2 = DB
|
||||||
|
} else {
|
||||||
|
db2 = DB.Debug()
|
||||||
|
}
|
||||||
|
result := db2.Where("id = ? and auth_id = ?", id, authId).Delete(&Shell{})
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
log.Printf("DeleteShellByID failed: %v", result.Error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteShellByIDV2(id uint) bool {
|
||||||
|
var db2 *gorm.DB
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
db2 = DB
|
||||||
|
} else {
|
||||||
|
db2 = DB.Debug()
|
||||||
|
}
|
||||||
|
result := db2.Where("id = ? ", id).Delete(&Shell{})
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
log.Printf("DeleteShellByID failed: %v", result.Error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
74
dao/user.go
74
dao/user.go
|
|
@ -35,7 +35,10 @@ func CreateUser(name, password, email, gender string, age int) uint {
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteUserByID(id int) int {
|
func DeleteUserByID(id int) int {
|
||||||
DB.Delete(&User{}, id)
|
res := DB.Delete(&User{}, id)
|
||||||
|
if res.Error != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,7 +84,7 @@ func UpdateUserByID(id int, name, password, email string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 管理员修改用户信息
|
// 管理员修改用户信息
|
||||||
func UpdateUserByID2(id int, req proto.UpdateUserInfoReq) {
|
func UpdateUserByID2(id int, req proto.UpdateUserInfoReq) error {
|
||||||
updateData := make(map[string]interface{})
|
updateData := make(map[string]interface{})
|
||||||
updateData["Name"] = req.Username
|
updateData["Name"] = req.Username
|
||||||
updateData["Age"] = req.Age
|
updateData["Age"] = req.Age
|
||||||
|
|
@ -94,10 +97,71 @@ func UpdateUserByID2(id int, req proto.UpdateUserInfoReq) {
|
||||||
updateData["CIDFunc"] = req.CIDFunc
|
updateData["CIDFunc"] = req.CIDFunc
|
||||||
updateData["Avatar"] = req.Avatar
|
updateData["Avatar"] = req.Avatar
|
||||||
updateData["Gender"] = req.Gender
|
updateData["Gender"] = req.Gender
|
||||||
DB.Model(&User{}).Where("id =?", id).Updates(updateData)
|
res := DB.Model(&User{}).Where("id =?", id).Updates(updateData)
|
||||||
|
if res.Error != nil {
|
||||||
|
return res.Error
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用户修改自己的信息
|
// 用户修改自己的信息
|
||||||
func UpdateUserByID3(id int, req proto.UpdateUserInfoReq) {
|
func UpdateUserByID3(id int, req proto.UpdateUserInfoReq) error {
|
||||||
DB.Model(&User{}).Where("id = ?", id).Updates(User{Name: req.Username, Age: req.Age, Avatar: req.Avatar, Gender: req.Gender})
|
res := DB.Model(&User{}).Where("id = ?", id).Updates(User{Name: req.Username, Age: req.Age, Avatar: req.Avatar, Gender: req.Gender})
|
||||||
|
return res.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户数据同步-添加
|
||||||
|
func AddUserSync(req proto.UserAddOrUpdate) uint {
|
||||||
|
res := DB.Exec("insert into users (id, created_at, updated_at, deleted_at, name, age, email, password,gender,role,redis,run,upload,video_func,device_func,cid_func,avatar,create_time,update_time) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", req.ID, req.CreatedAt, req.UpdatedAt, req.DeletedAt, req.Name, req.Age, req.Email, req.Password, req.Gender, req.Role, req.Redis, req.Run, req.Upload, req.VideoFunc, req.DeviceFunc, req.CIDFunc, req.Avatar, req.CreateTime, req.UpdateTime)
|
||||||
|
if res.Error != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
res = DB.Debug().Exec("update users set deleted_at=null where id=?", req.ID)
|
||||||
|
if res.Error != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return req.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户数据同步-更新
|
||||||
|
func UpdateUserSync(req proto.UserAddOrUpdate) uint {
|
||||||
|
//事务
|
||||||
|
res := DB.Exec("update users set created_at=?, updated_at=?, deleted_at=?, name=?, age=?, email=?, password=?,gender=?,role=?,redis=?,run=?,upload=?,video_func=?,device_func=?,cid_func=?,avatar=?,create_time=?,update_time=? where id=?", req.CreatedAt, req.UpdatedAt, req.DeletedAt, req.Name, req.Age, req.Email, req.Password, req.Gender, req.Role, req.Redis, req.Run, req.Upload, req.VideoFunc, req.DeviceFunc, req.CIDFunc, req.Avatar, req.CreateTime, req.UpdateTime, req.ID)
|
||||||
|
if res.Error != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
res = DB.Debug().Exec("update users set deleted_at=null where id=?", req.ID)
|
||||||
|
if res.Error != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return req.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户数据同步-删除
|
||||||
|
func DeleteUserSync(req proto.UserDelID) uint {
|
||||||
|
res := DB.Delete(&User{}, req.ID)
|
||||||
|
if res.Error != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return req.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有用户
|
||||||
|
func GetAllUser() []User {
|
||||||
|
var users []User
|
||||||
|
DB.Find(&users)
|
||||||
|
return users
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户数据同步
|
||||||
|
type UserSyncResp struct {
|
||||||
|
Update []User `json:"update" form:"update"` //更新用户
|
||||||
|
Add []User `json:"add" form:"add"` //添加用户
|
||||||
|
Delete []proto.UserDelID `json:"delete" form:"delete"` //删除用户
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空用户表
|
||||||
|
func ClearAllUsers() error {
|
||||||
|
res := DB.Exec("TRUNCATE TABLE users")
|
||||||
|
return res.Error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
101
dao/video.go
101
dao/video.go
|
|
@ -1,8 +1,9 @@
|
||||||
package dao
|
package dao
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"time"
|
"videoplayer/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Video struct {
|
type Video struct {
|
||||||
|
|
@ -21,35 +22,80 @@ type Video struct {
|
||||||
|
|
||||||
func FindWillDelVideoList(id int) []Video {
|
func FindWillDelVideoList(id int) []Video {
|
||||||
var videos []Video
|
var videos []Video
|
||||||
DB.Where("auth_id = ?", id).Where("delete_time<=now()").Where("isdelete=0").Find(&videos)
|
DB.Raw("select * from videos where auth_id = ? and delete_time<=now() and isdelete=0", id).Scan(&videos)
|
||||||
return videos
|
return videos
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateVideo(videoPath, videoName string, cameraID, authID, human, isDelete int, createTime, endTime, deleteTime string, fileSize int) uint {
|
func CreateVideo(videoPath, videoName string, cameraID, authID, human, isDelete int, createTime, endTime, deleteTime string, fileSize int) uint {
|
||||||
video := Video{VideoPath: videoPath, VideoName: videoName, CameraID: cameraID, AuthId: authID, Human: human, IsDelete: isDelete, CreateTime: createTime, EndTime: endTime, DeleteTime: deleteTime, FileSize: fileSize}
|
video := Video{VideoPath: videoPath, VideoName: videoName, CameraID: cameraID, AuthId: authID, Human: human, IsDelete: isDelete, CreateTime: createTime, EndTime: endTime, DeleteTime: deleteTime, FileSize: fileSize}
|
||||||
res := DB.Create(&video)
|
var res *gorm.DB
|
||||||
if res.Error != nil {
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
return 0
|
res = DB.Debug().Create(&video)
|
||||||
}
|
if res.Error != nil {
|
||||||
if deleteTime == "" {
|
return 0
|
||||||
DB.Exec("update videos set delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY) where id=?", video.ID) //delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY)
|
}
|
||||||
|
if deleteTime == "" {
|
||||||
|
DB.Debug().Exec("update videos set delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY) where id=?", video.ID) //delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res = DB.Create(&video)
|
||||||
|
if res.Error != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if deleteTime == "" {
|
||||||
|
DB.Exec("update videos set delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY) where id=?", video.ID) //delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return video.ID
|
return video.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 文件已删除
|
||||||
func DeleteVideoByID(id, user int) int {
|
func DeleteVideoByID(id, user int) int {
|
||||||
delete_time := time.Now().Format("2006-01-02 15:04:05")
|
var res *gorm.DB
|
||||||
DB.Where("id = ? and auth_id = ?", id, user).Updates(&Video{DeleteTime: delete_time, IsDelete: 1})
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
DB.Where("id = ? and auth_id = ?", id, user).Delete(&Video{})
|
res = DB.Debug().Exec("update videos set deleted_at = now(),isdelete=1 where id=? and auth_id=?", id, user)
|
||||||
|
} else {
|
||||||
|
res = DB.Exec("update videos set deleted_at = now(),isdelete=1 where id=? and auth_id=?", id, user) //delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY)
|
||||||
|
}
|
||||||
|
if res.Error != nil {
|
||||||
|
fmt.Println("dao DeleteVideoByID:", res.Error)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件未删除时逻辑删除
|
||||||
|
func LogicDeleteVideoByID(id, user int) int {
|
||||||
|
var res *gorm.DB
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
res = DB.Debug().Exec("update videos set deleted_at=now(),delete_time=now() where id=? and auth_id=?", id, user)
|
||||||
|
} else {
|
||||||
|
res = DB.Exec("update videos set deleted_at=now(),delete_time=now() where id=? and auth_id=?", id, user)
|
||||||
|
}
|
||||||
|
if res.Error != nil {
|
||||||
|
fmt.Println("dao LogicDeleteVideoByID:", res.Error)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回滚视频输出-逻辑删除,若文件已删除则不可回滚
|
||||||
|
func RollbackVideoByID(id, user int) int {
|
||||||
|
res := DB.Exec("update videos set deleted_at=null where id=? and auth_id=? and isdelete=0", id, user) //isdelete=0说明文件未删除
|
||||||
|
if res.Error != nil {
|
||||||
|
fmt.Println("dao RollbackVideoByID:", res.Error)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateVideo(videoPath, videoName string, cameraID, videoID, authID, human, isDelete int, createTime, endTime string, fileSize int) bool {
|
func UpdateVideo(videoPath, videoName string, cameraID, videoID, authID, human, isDelete int, createTime, endTime string, fileSize int) bool {
|
||||||
res := DB.Model(&Video{}).Where("id = ? and auth_id = ?", videoID, authID).Updates(Video{VideoPath: videoPath, VideoName: videoName, CameraID: cameraID, AuthId: authID, Human: human, IsDelete: isDelete, CreateTime: createTime, EndTime: endTime, FileSize: fileSize})
|
var res *gorm.DB
|
||||||
if res.Error != nil {
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
return false
|
res = DB.Debug().Model(&Video{}).Where("id = ? and auth_id = ?", videoID, authID).Updates(Video{VideoPath: videoPath, VideoName: videoName, CameraID: cameraID, AuthId: authID, Human: human, IsDelete: isDelete, CreateTime: createTime, EndTime: endTime, FileSize: fileSize})
|
||||||
|
} else {
|
||||||
|
res = DB.Model(&Video{}).Where("id = ? and auth_id = ?", videoID, authID).Updates(Video{VideoPath: videoPath, VideoName: videoName, CameraID: cameraID, AuthId: authID, Human: human, IsDelete: isDelete, CreateTime: createTime, EndTime: endTime, FileSize: fileSize})
|
||||||
}
|
}
|
||||||
res = DB.Exec("update videos set delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY) where id=? and auth_id=?", videoID, authID) //delete_time= DATE_ADD(NOW(), INTERVAL 20 DAY)
|
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -65,13 +111,34 @@ func FindVideoByID(id, auth_id int) Video {
|
||||||
// 根据用户id查找视频列表,返回最新30条
|
// 根据用户id查找视频列表,返回最新30条
|
||||||
func FindVideoListsByAuthID(auth_id int) []Video {
|
func FindVideoListsByAuthID(auth_id int) []Video {
|
||||||
var videos []Video
|
var videos []Video
|
||||||
DB.Where("auth_id = ? and isdelete =? ", auth_id, 0).Order("created_at DESC").Limit(30).Find(&videos)
|
DB.Where("auth_id = ? and isdelete =? ", auth_id, 0).Order("create_time DESC").Limit(30).Find(&videos)
|
||||||
|
return videos
|
||||||
|
}
|
||||||
|
|
||||||
|
// 管理员查找视频,可查找所有视频
|
||||||
|
func FindVideoByID2(id int) []Video {
|
||||||
|
var videos []Video
|
||||||
|
var err error
|
||||||
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
res := DB.Debug().Raw("select * from videos where id = ?", id).Scan(&videos)
|
||||||
|
err = res.Error
|
||||||
|
} else {
|
||||||
|
res := DB.Raw("select * from videos where id = ?", id).Scan(&videos)
|
||||||
|
err = res.Error
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return videos
|
return videos
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindVideoListByTime(auth_id int, startTime, endTime string) []Video {
|
func FindVideoListByTime(auth_id int, startTime, endTime string) []Video {
|
||||||
var videos []Video
|
var videos []Video
|
||||||
DB.Where("auth_id = ?", auth_id).Where("isdelete=0").Where("created_at > ? and created_at < ?", startTime, endTime).Find(&videos)
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
|
DB.Debug().Where("auth_id = ?", auth_id).Where("create_time > ? and create_time < ? and isdelete=0", startTime, endTime).Find(&videos)
|
||||||
|
} else {
|
||||||
|
DB.Where("auth_id = ?", auth_id).Where("create_time > ? and create_time < ? and isdelete=0", startTime, endTime).Find(&videos)
|
||||||
|
}
|
||||||
return videos
|
return videos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,10 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
"videoplayer/dao"
|
"videoplayer/dao"
|
||||||
"videoplayer/proto"
|
"videoplayer/proto"
|
||||||
|
"videoplayer/service"
|
||||||
"videoplayer/worker"
|
"videoplayer/worker"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -53,6 +55,7 @@ func SetUpCIDGroup(router *gin.Engine) {
|
||||||
cidGroup.POST("/run", RunCID)
|
cidGroup.POST("/run", RunCID)
|
||||||
cidGroup.POST("/log", GetCIDLogList) //获取执行日志
|
cidGroup.POST("/log", GetCIDLogList) //获取执行日志
|
||||||
cidGroup.POST("/log/detail", GetCIDLog) //获取执行日志详情
|
cidGroup.POST("/log/detail", GetCIDLog) //获取执行日志详情
|
||||||
|
cidGroup.GET("/callback", CIDCallback)
|
||||||
cidGroup.POST("/callback", CIDCallback)
|
cidGroup.POST("/callback", CIDCallback)
|
||||||
}
|
}
|
||||||
func RunCID(c *gin.Context) {
|
func RunCID(c *gin.Context) {
|
||||||
|
|
@ -60,7 +63,8 @@ func RunCID(c *gin.Context) {
|
||||||
id, _ := c.Get("id")
|
id, _ := c.Get("id")
|
||||||
authID := int(id.(float64))
|
authID := int(id.(float64))
|
||||||
//获取权限
|
//获取权限
|
||||||
user := dao.FindUserByUserID(authID)
|
//user := dao.FindUserByUserID(authID)
|
||||||
|
user := service.GetUserByIDFromUserCenter(authID)
|
||||||
if user.Run == false {
|
if user.Run == false {
|
||||||
c.JSON(200, gin.H{"error": "no run Permissions", "code": proto.NoRunPermissions, "message": "no run Permissions"})
|
c.JSON(200, gin.H{"error": "no run Permissions", "code": proto.NoRunPermissions, "message": "no run Permissions"})
|
||||||
return
|
return
|
||||||
|
|
@ -181,7 +185,7 @@ func CIDCallback(c *gin.Context) {
|
||||||
// 获取用户ID
|
// 获取用户ID
|
||||||
token := c.Query("token")
|
token := c.Query("token")
|
||||||
cid_id := c.Query("id")
|
cid_id := c.Query("id")
|
||||||
fmt.Println("token:", token, "cid_id:", cid_id)
|
//fmt.Println("token:", token, "cid_id:", cid_id)
|
||||||
//将cid转换为int
|
//将cid转换为int
|
||||||
cid, _ := strconv.Atoi(cid_id)
|
cid, _ := strconv.Atoi(cid_id)
|
||||||
|
|
||||||
|
|
@ -195,7 +199,8 @@ func CIDCallback(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user := dao.FindUserByUserID(res.Auth_id)
|
//user := dao.FindUserByUserID(res.Auth_id)
|
||||||
|
user := service.GetUserByIDFromUserCenter(res.Auth_id)
|
||||||
if user.Run == false {
|
if user.Run == false {
|
||||||
c.JSON(200, gin.H{"error": "no run Permissions", "code": proto.NoRunPermissions, "message": "the user has no run Permissions"})
|
c.JSON(200, gin.H{"error": "no run Permissions", "code": proto.NoRunPermissions, "message": "the user has no run Permissions"})
|
||||||
return
|
return
|
||||||
|
|
@ -221,6 +226,7 @@ func RunShell(username, url, script string, id, authID int) {
|
||||||
echo "start"
|
echo "start"
|
||||||
` + script + `
|
` + script + `
|
||||||
echo "end"`
|
echo "end"`
|
||||||
|
start := time.Now()
|
||||||
//执行脚本
|
//执行脚本
|
||||||
cmd := exec.Command("/bin/bash", "-c", scriptContent)
|
cmd := exec.Command("/bin/bash", "-c", scriptContent)
|
||||||
// 使用bytes.Buffer捕获输出
|
// 使用bytes.Buffer捕获输出
|
||||||
|
|
@ -231,8 +237,9 @@ echo "end"`
|
||||||
if err3 != nil {
|
if err3 != nil {
|
||||||
err3_info = err3.Error()
|
err3_info = err3.Error()
|
||||||
}
|
}
|
||||||
|
elapsed := time.Since(start)
|
||||||
//fmt.Println("bash content:", scriptContent)
|
//fmt.Println("bash content:", scriptContent)
|
||||||
dao.CreateRunLog(id, authID, scriptContent, out.String(), err3_info) //添加执行日志
|
dao.CreateRunLog(id, authID, scriptContent, out.String(), err3_info, elapsed.Seconds()) //添加执行日志
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定时任务处理逻辑
|
// 定时任务处理逻辑
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@ package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -60,7 +62,7 @@ func SetUpDeviceGroup(router *gin.Engine) {
|
||||||
deviceGroup.POST("/update_device", UpdateDevice)
|
deviceGroup.POST("/update_device", UpdateDevice)
|
||||||
deviceGroup.POST("/delete_device", DeleteDevice)
|
deviceGroup.POST("/delete_device", DeleteDevice)
|
||||||
deviceGroup.GET("/get_real_time_image", GetRealTimeImage)
|
deviceGroup.GET("/get_real_time_image", GetRealTimeImage)
|
||||||
|
deviceGroup.GET("/video_feed", VideoFeed)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteDevice(c *gin.Context) {
|
func DeleteDevice(c *gin.Context) {
|
||||||
|
|
@ -227,7 +229,69 @@ func GetRealTimeImage(c *gin.Context) {
|
||||||
}
|
}
|
||||||
worker.SetRedisWithExpire(strconv.Itoa(int(device.ID))+"_is_play", "1", time.Minute*5)
|
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")
|
fmt.Println("device_id:", device_id_int, " has set is_play to 1")
|
||||||
go subscribeAndHandleMessages(ws, device_id_int)
|
go subscribeAndHandleMessagesV2(ws, device_id_int)
|
||||||
|
}
|
||||||
|
|
||||||
|
func subscribeAndHandleMessagesV2(ws *websocket.Conn, device_id int) {
|
||||||
|
ctx := context.Background()
|
||||||
|
pubsub := worker.RedisClient.Subscribe(ctx, strconv.Itoa(device_id)+"_frames_msgs")
|
||||||
|
// 生成唯一连接 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)
|
||||||
|
defer pubsub.Close()
|
||||||
|
defer ws.Close()
|
||||||
|
ch := pubsub.Channel()
|
||||||
|
var ticker *time.Ticker // 定时器, 用于发送心跳包, 防止连接断开,每秒发送一次
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case msg, _ := <-ch:
|
||||||
|
frame := ""
|
||||||
|
if msg.Payload != "" {
|
||||||
|
frame = msg.Payload
|
||||||
|
}
|
||||||
|
//将base64图片数据解析为图片
|
||||||
|
buf, err := base64.StdEncoding.DecodeString(frame)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("base64 decode error:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err2 := ws.WriteMessage(websocket.BinaryMessage, buf)
|
||||||
|
if err2 != nil {
|
||||||
|
clientsMux.Lock()
|
||||||
|
clients[ws] = false
|
||||||
|
clientsMux.Unlock()
|
||||||
|
fmt.Println("send message to client err:", err2)
|
||||||
|
worker.SetRedisSetRemove(online_conn_key, con_id)
|
||||||
|
goto end
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if ticker == nil {
|
||||||
|
ticker = time.NewTicker(time.Second)
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
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
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func subscribeAndHandleMessages(ws *websocket.Conn, device_id int) {
|
func subscribeAndHandleMessages(ws *websocket.Conn, device_id int) {
|
||||||
|
|
@ -301,3 +365,126 @@ end:
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VideoFeed 函数用于处理视频流的获取与返回,支持根据前端连接情况控制发送
|
||||||
|
func VideoFeed(c *gin.Context) {
|
||||||
|
// 更严谨地获取并转换 id 参数,处理可能的错误
|
||||||
|
id, ok := c.Get("id")
|
||||||
|
if !ok {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"code": proto.DataNotFound, "message": "id not found in context"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
floatId, ok := id.(float64)
|
||||||
|
if !ok {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"code": proto.DataFormatError, "message": "invalid id type in context"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
user_id := int(floatId)
|
||||||
|
|
||||||
|
device_id := c.Query("device_id")
|
||||||
|
device_id_int, err := strconv.Atoi(device_id)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"code": proto.DataFormatError, "message": "invalid device_id format"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Header("Content-Type", "multipart/x-mixed-replace; boundary=frame") // 设置响应头
|
||||||
|
|
||||||
|
device := service.GetDevice(device_id_int, user_id)
|
||||||
|
if device.ID == 0 {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.DataNotFound, "message": "device not found"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在 Redis 中设置设备正在播放状态及过期时间,处理设置失败的情况
|
||||||
|
isSuccess := worker.SetRedisWithExpire(strconv.Itoa(int(device.ID))+"_is_play", "1", time.Minute*5)
|
||||||
|
if isSuccess == false {
|
||||||
|
fmt.Println("set redis is_play error:", err)
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"code": proto.OperationFailed, "message": "failed to set device play status in Redis"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("device_id:", device_id_int, " has set is_play to 1")
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
pubSub := worker.RedisClient.Subscribe(ctx, strconv.Itoa(device_id_int)+"_frames_msgs")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
err = pubSub.Close()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("close pubSub error:", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 生成唯一连接 uuid
|
||||||
|
//conId := uuid.New().String()
|
||||||
|
//onlineConnKey := "device_" + strconv.Itoa(device_id_int) + "_online_conn_ids"
|
||||||
|
//// 加入设备在线连接集合,处理添加失败的情况
|
||||||
|
//worker.SetRedisSetAdd(onlineConnKey, conId)
|
||||||
|
|
||||||
|
// 创建一个通道用于接收客户端连接关闭的信号
|
||||||
|
clientClosed := make(chan struct{})
|
||||||
|
defer close(clientClosed)
|
||||||
|
c.Stream(func(w io.Writer) bool {
|
||||||
|
// 将读取 Redis 消息通道的逻辑放在这里,方便根据返回值控制循环
|
||||||
|
ch := pubSub.Channel()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case msg, ok := <-ch:
|
||||||
|
if !ok {
|
||||||
|
// 如果 Redis 通道关闭,进行相应处理并返回 false 停止发送
|
||||||
|
fmt.Println("Redis channel closed unexpectedly")
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"code": proto.RedisSetError, "message": "Redis channel closed"})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 将 base64 图片数据解析为图片
|
||||||
|
frame := msg.Payload
|
||||||
|
buf, err := base64.StdEncoding.DecodeString(frame)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("base64 decode error:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// 按照视频流格式要求构造并返回响应数据
|
||||||
|
_, err = w.Write([]byte("--frame\r\n"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("write video frame error:", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, err = w.Write([]byte("Content-Type: image/jpeg\r\n\r\n"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("write video frame error:", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, err = w.Write(buf)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("write video frame error:", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, err = w.Write([]byte("\r\n"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("write video frame error:", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case <-clientClosed:
|
||||||
|
// 当接收到客户端关闭连接的信号,返回 false 停止发送视频流
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 启动一个协程来监测客户端连接是否关闭,关闭时向 clientClosed 通道发送信号
|
||||||
|
go func() {
|
||||||
|
<-c.Request.Context().Done()
|
||||||
|
//如果clientClosed通道已经关闭,不再发送
|
||||||
|
if _, ok := <-clientClosed; !ok {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
clientClosed <- struct{}{}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 查看是否还有其他连接,没有则设置 is_play 为 0
|
||||||
|
//if worker.IsContainKey(onlineConnKey) == false {
|
||||||
|
// worker.SetRedisWithExpire(strconv.Itoa(device_id_int)+"_is_play", "0", time.Minute*5)
|
||||||
|
// fmt.Println("device_id:", device_id, " has set is_play to 0")
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,194 @@
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
"videoplayer/dao"
|
||||||
|
"videoplayer/proto"
|
||||||
|
"videoplayer/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetUpFileGroup(router *gin.Engine) {
|
||||||
|
fileGroup := router.Group("/file")
|
||||||
|
fileGroup.POST("/config_add", AddConfigFile)
|
||||||
|
fileGroup.POST("/config_delete", DeleteConfigFile)
|
||||||
|
fileGroup.POST("/config_update", UpdateConfigFile)
|
||||||
|
fileGroup.POST("/config_search", SearchConfigFile)
|
||||||
|
fileGroup.POST("/upload", UploadFileV2)
|
||||||
|
fileGroup.GET("/general/:filename", GetFile)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddConfigFile(c *gin.Context) {
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
user_id := int(id.(float64))
|
||||||
|
var req proto.AddConfigFileReq
|
||||||
|
if err := c.ShouldBind(&req); err == nil {
|
||||||
|
err2 := service.CreateConfigFile(&req, user_id)
|
||||||
|
if err2 != nil {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "add config file failed:" + err2.Error(), "code": proto.AddConfigFileFailed, "message": "failed"})
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "upload form parameter decode error:" + err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteConfigFile(c *gin.Context) {
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
user_id := int(id.(float64))
|
||||||
|
var req proto.ConfigFileReq
|
||||||
|
if err := c.ShouldBind(&req); err == nil {
|
||||||
|
err2 := service.DeleteConfigFile(&req, user_id)
|
||||||
|
if err2 != nil {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "delete config file failed:" + err2.Error(), "code": proto.DeleteConfigFailed, "message": "failed"})
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "upload form parameter decode error:" + err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateConfigFile(c *gin.Context) {
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
user_id := int(id.(float64))
|
||||||
|
var req proto.ConfigFileReq
|
||||||
|
if err := c.ShouldBind(&req); err == nil {
|
||||||
|
var configFileService service.ConfigFileService
|
||||||
|
err2 := configFileService.UpdateConfigFile(&req, user_id)
|
||||||
|
if err2 != nil {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "update config file failed:" + err2.Error(), "code": proto.UpdateConfigFailed, "message": "failed"})
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "upload form parameter decode error:" + err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SearchConfigFile(c *gin.Context) {
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
user_id := int(id.(float64))
|
||||||
|
var req proto.ConfigFileReq
|
||||||
|
if err := c.ShouldBind(&req); err == nil {
|
||||||
|
var configFileService service.ConfigFileService
|
||||||
|
if req.Type == "one" {
|
||||||
|
//有文件内容
|
||||||
|
configFile, err2 := configFileService.SearchOneConfigFile(&req, user_id)
|
||||||
|
if err2 == nil {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "msg": "success", "data": configFile})
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SearchConfigFileFailed, "msg": "info:" + err2.Error(), "data": configFile})
|
||||||
|
}
|
||||||
|
} else if req.Type == "all" {
|
||||||
|
configFileList, err3 := configFileService.SearchAllConfigFile(user_id)
|
||||||
|
if err3 == nil {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "msg": "success", "data": configFileList})
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SearchConfigFileFailed, "msg": "info:" + err3.Error(), "data": configFileList})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "search config file type error", "code": proto.ParameterError, "message": "failed"})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "upload form parameter decode error:" + err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UploadFileV2(c *gin.Context) {
|
||||||
|
//先查看是否有权限
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
id1 := int(id.(float64))
|
||||||
|
|
||||||
|
var req proto.FileUploadReq
|
||||||
|
//获取post form参数
|
||||||
|
if err := c.ShouldBind(&req); err == nil {
|
||||||
|
//检查参数
|
||||||
|
if err2 := service.CheckUploadRequestParameters(&req); err2 != nil {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "upload form parameter check error:" + err2.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//
|
||||||
|
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "upload form parameter decode error:" + err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//从请求头获取upload_type
|
||||||
|
uploadType := c.PostForm("upload_type")
|
||||||
|
authType := c.PostForm("auth_type")
|
||||||
|
md5_ := c.PostForm("md5")
|
||||||
|
if uploadType == "" {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "upload_type is empty", "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user := dao.FindUserByUserID(id1)
|
||||||
|
if user.Upload == false {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "no upload Permissions", "code": proto.NoUploadPermissions, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//上传文件
|
||||||
|
file, err := c.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "upload file failed", "code": proto.UploadFileFailed, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//计算文件md5值
|
||||||
|
if md5_ == "" {
|
||||||
|
file_, _ := file.Open()
|
||||||
|
md5_ = service.CalculateFileMd5(file_)
|
||||||
|
if md5_ == "" {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "计算文件MD5值失败", "code": proto.UploadFileFailed, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//查询文件是否已存在
|
||||||
|
fileExist := dao.FindFileByMd5(md5_)
|
||||||
|
if fileExist.ID != 0 {
|
||||||
|
fileExist.FilePath = ""
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": fileExist})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//保存文件
|
||||||
|
filePath, fileStoreName, err := service.SaveFile(c, file, uploadType)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "save file failed", "code": proto.SaveFileFailed, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//保存文件信息
|
||||||
|
fileSize := int(file.Size)
|
||||||
|
fileName := file.Filename
|
||||||
|
fileType := file.Header.Get("file_type")
|
||||||
|
var auth_type_ bool
|
||||||
|
if authType == "public" || authType == "" {
|
||||||
|
auth_type_ = false
|
||||||
|
} else if authType == "private" {
|
||||||
|
auth_type_ = true
|
||||||
|
}
|
||||||
|
file_record := dao.CreateFile(fileStoreName, fileName, fileType, filePath, md5_, fileSize, id1, auth_type_)
|
||||||
|
if file_record.ID == 0 {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "save file info failed", "code": proto.SaveFileInfoFailed, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file_record.FilePath = ""
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": file_record})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
"videoplayer/proto"
|
||||||
|
"videoplayer/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ShellHandler struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateShellReq struct {
|
||||||
|
ShellName string `json:"shell_name" form:"shell_name" binding:"required"`
|
||||||
|
ShellContent string `json:"shell_content" form:"shell_content" binding:"required"`
|
||||||
|
Server string `json:"server" form:"server" binding:"required"`
|
||||||
|
}
|
||||||
|
type UpdateShellReq struct {
|
||||||
|
ID uint `json:"id" form:"id" binding:"required"`
|
||||||
|
ShellName string `json:"shell_name" form:"shell_name"`
|
||||||
|
ShellContent string `json:"shell_content" form:"shell_content"`
|
||||||
|
Server string `json:"server" form:"server"`
|
||||||
|
Status int `json:"status" form:"status"`
|
||||||
|
ShellResult string `json:"shell_result" form:"shell_result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateShellReqV2 struct {
|
||||||
|
Shells []UpdateShellReq `json:"shells" form:"shells"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateShellResp struct {
|
||||||
|
ID uint `json:"id" form:"id"`
|
||||||
|
Status int `json:"status" form:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeleteShellRequestID struct {
|
||||||
|
ID uint `json:"id" form:"id" binding:"required"`
|
||||||
|
}
|
||||||
|
type DeleteShellRequest struct {
|
||||||
|
Shells []DeleteShellRequestID `json:"shells" form:"shells" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetUpShellGroup(router *gin.Engine) {
|
||||||
|
shellGroup := router.Group("/shell") //持续集成、部署
|
||||||
|
shellHandler := ShellHandler{}
|
||||||
|
shellGroup.POST("/create", shellHandler.CreateShell)
|
||||||
|
shellGroup.POST("/list", shellHandler.ListShell)
|
||||||
|
shellGroup.POST("/update", shellHandler.UpdateShell)
|
||||||
|
shellGroup.POST("/delete", shellHandler.DeleteShell)
|
||||||
|
shellGroup.POST("/server_will_run_list", shellHandler.ServerWillRun)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ShellHandler) CreateShell(c *gin.Context) {
|
||||||
|
user_id, _ := c.Get("id")
|
||||||
|
uid := int(user_id.(float64))
|
||||||
|
var req CreateShellReq
|
||||||
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.ShellCreateFailed, "message": "参数错误", "data": err.Error()})
|
||||||
|
} else {
|
||||||
|
id := service.CreateShell(req.ShellName, req.ShellContent, req.Server, uid)
|
||||||
|
if id == 0 {
|
||||||
|
c.JSON(200, gin.H{"code": proto.ShellCreateFailed, "message": "创建失败,id is 0", "data": ""})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "创建成功", "data": id})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ShellHandler) ListShell(c *gin.Context) {
|
||||||
|
userId, _ := c.Get("id")
|
||||||
|
id := int(userId.(float64))
|
||||||
|
shells := service.FindShellByAuthID(id)
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "获取成功", "data": shells})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ShellHandler) UpdateShell(c *gin.Context) {
|
||||||
|
var req UpdateShellReqV2
|
||||||
|
userId, _ := c.Get("id")
|
||||||
|
id := int(userId.(float64))
|
||||||
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.ShellUpdateFailed, "message": "参数错误", "data": err.Error()})
|
||||||
|
} else {
|
||||||
|
var resp []UpdateShellResp
|
||||||
|
//log.Println("UpdateShellReqData:", req.Shells)
|
||||||
|
for _, v := range req.Shells {
|
||||||
|
if service.UpdateShellByID(v.ID, uint(id), v.ShellName, v.ShellContent, v.Server, v.Status, v.ShellResult) {
|
||||||
|
resp = append(resp, UpdateShellResp{ID: v.ID, Status: v.Status})
|
||||||
|
} else {
|
||||||
|
resp = append(resp, UpdateShellResp{ID: v.ID, Status: -1})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "更新成功", "data": resp})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeleteShellResp struct {
|
||||||
|
Success []DeleteShellRequestID `json:"success" form:"success"`
|
||||||
|
Error []DeleteShellRequestID `json:"error" form:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ShellHandler) DeleteShell(c *gin.Context) {
|
||||||
|
userId, _ := c.Get("id")
|
||||||
|
id := int(userId.(float64))
|
||||||
|
var req DeleteShellRequest
|
||||||
|
var resp proto.GeneralResp
|
||||||
|
|
||||||
|
if err := c.ShouldBind(&req); err == nil {
|
||||||
|
var delSuccessIDs []DeleteShellRequestID
|
||||||
|
var delErrorIDs []DeleteShellRequestID
|
||||||
|
for _, v := range req.Shells {
|
||||||
|
delSuccess := service.DeleteShellByID(v.ID, uint(id))
|
||||||
|
if delSuccess {
|
||||||
|
delSuccessIDs = append(delSuccessIDs, v)
|
||||||
|
} else {
|
||||||
|
delErrorIDs = append(delErrorIDs, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var delResp DeleteShellResp
|
||||||
|
delResp.Success = delSuccessIDs
|
||||||
|
delResp.Error = delErrorIDs
|
||||||
|
resp.Code = proto.SuccessCode
|
||||||
|
resp.Data = delResp
|
||||||
|
resp.Message = "success"
|
||||||
|
} else {
|
||||||
|
resp.Code = proto.ParameterError
|
||||||
|
resp.Message = "参数解析错误:" + err.Error()
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerWillRunReq struct {
|
||||||
|
Server string `json:"server"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ShellHandler) ServerWillRun(c *gin.Context) {
|
||||||
|
userId, _ := c.Get("id")
|
||||||
|
id := int(userId.(float64))
|
||||||
|
var req ServerWillRunReq
|
||||||
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.ShellUpdateFailed, "message": "参数错误", "data": err.Error()})
|
||||||
|
} else {
|
||||||
|
//log.Printf("ServerWillRunReq:%s,id:%d", req.Server, id)
|
||||||
|
willRunShells, err2 := service.FindShellWillRunByServer(req.Server, id)
|
||||||
|
if err2 != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.ShellUpdateFailed, "message": "获取失败", "data": err2.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "获取成功", "data": willRunShells})
|
||||||
|
}
|
||||||
|
}
|
||||||
254
handler/tool.go
254
handler/tool.go
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -26,6 +27,17 @@ type SetDeviceStatusReq struct {
|
||||||
Status string `json:"status" form:"status"` //设备状态
|
Status string `json:"status" form:"status"` //设备状态
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GetFileListReq struct {
|
||||||
|
Type string `json:"type" form:"type"` //请求类型,1:按md5查询,2:按文件名查询;3:查询待删除文件
|
||||||
|
Md5 string `json:"md5" form:"md5"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SendMailReq struct {
|
||||||
|
Title string `json:"title" form:"title"`
|
||||||
|
Content string `json:"content" form:"content"`
|
||||||
|
To string `json:"to" form:"to"`
|
||||||
|
}
|
||||||
|
|
||||||
func SetUpToolGroup(router *gin.Engine) {
|
func SetUpToolGroup(router *gin.Engine) {
|
||||||
toolGroup := router.Group("/tool")
|
toolGroup := router.Group("/tool")
|
||||||
toolGroup.POST("/set_redis", SetRedis)
|
toolGroup.POST("/set_redis", SetRedis)
|
||||||
|
|
@ -34,40 +46,150 @@ func SetUpToolGroup(router *gin.Engine) {
|
||||||
//文件上传、下载
|
//文件上传、下载
|
||||||
toolGroup.POST("/upload", UploadFile)
|
toolGroup.POST("/upload", UploadFile)
|
||||||
toolGroup.GET("/download", DownloadFile)
|
toolGroup.GET("/download", DownloadFile)
|
||||||
|
toolGroup.GET("/file/:filename", GetFile)
|
||||||
|
toolGroup.POST("/file_list", GetFileList)
|
||||||
//文件管理
|
//文件管理
|
||||||
toolGroup.POST("/file_del", DelFile)
|
toolGroup.POST("/file_del", DelFile)
|
||||||
//服务器、设备状态接口
|
//服务器、设备状态接口
|
||||||
toolGroup.POST("/monitor", SetDeviceStatusV2)
|
toolGroup.POST("/monitor", SetDeviceStatusV2)
|
||||||
|
toolGroup.GET("/get_monitor_list", GetMonitorList) //获取设备监控列表
|
||||||
|
toolGroup.POST("/update_monitor", UpdateMonitor) //设置设备状态
|
||||||
|
toolGroup.POST("/del_monitor", DelMonitor) //删除设备监控
|
||||||
|
//发送邮件
|
||||||
|
toolGroup.POST("/send_mail", SendMailTool)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMonitorList(c *gin.Context) {
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
userId := int(id.(float64))
|
||||||
|
var resp proto.GeneralResp
|
||||||
|
monitorDeviceList, err := service.GetMonitorDeviceListWithStatus(userId)
|
||||||
|
if err != nil {
|
||||||
|
resp.Code = proto.OperationFailed
|
||||||
|
resp.Message = err.Error()
|
||||||
|
} else {
|
||||||
|
resp.Code = proto.SuccessCode
|
||||||
|
resp.Message = "success"
|
||||||
|
resp.Data = monitorDeviceList
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateMonitorDeviceStatusReq struct {
|
||||||
|
Devices []proto.GetMonitorDeviceStatus `json:"devices" form:"devices"` //设备状态列表
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateMonitor(c *gin.Context) {
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
id1 := int(id.(float64))
|
||||||
|
var req UpdateMonitorDeviceStatusReq
|
||||||
|
var resp proto.GeneralResp
|
||||||
|
if err := c.ShouldBind(&req); err == nil {
|
||||||
|
err2 := service.UpdateMonitorDeviceListWithStatus(id1, req.Devices)
|
||||||
|
if err2 != nil {
|
||||||
|
resp.Code = proto.OperationFailed
|
||||||
|
resp.Message = "更新设备状态失败:" + err2.Error()
|
||||||
|
} else {
|
||||||
|
resp.Code = proto.SuccessCode
|
||||||
|
resp.Message = "更新设备状态成功"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resp.Code = proto.ParameterError
|
||||||
|
resp.Message = "参数解析失败:" + err.Error()
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, resp)
|
||||||
|
}
|
||||||
|
func DelMonitor(c *gin.Context) {
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
id1 := int(id.(float64))
|
||||||
|
var req UpdateMonitorDeviceStatusReq
|
||||||
|
var resp proto.GeneralResp
|
||||||
|
if err := c.ShouldBind(&req); err == nil {
|
||||||
|
delSuccess, err2 := service.DelMonitorDeviceListWithStatus(id1, req.Devices)
|
||||||
|
if err2 != nil {
|
||||||
|
resp.Code = proto.OperationFailed
|
||||||
|
resp.Message = "更新设备状态失败:" + err2.Error()
|
||||||
|
resp.Data = delSuccess
|
||||||
|
} else {
|
||||||
|
resp.Code = proto.SuccessCode
|
||||||
|
resp.Message = "更新设备状态成功"
|
||||||
|
resp.Data = delSuccess
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resp.Code = proto.ParameterError
|
||||||
|
resp.Message = "参数解析失败:" + err.Error()
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetDeviceStatusV2(c *gin.Context) {
|
func SetDeviceStatusV2(c *gin.Context) {
|
||||||
// TODO
|
// TODO
|
||||||
var req SetDeviceStatusReq
|
var req SetDeviceStatusReq
|
||||||
|
var resp proto.GeneralResp
|
||||||
if err := c.ShouldBind(&req); err != nil {
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
c.JSON(200, gin.H{"code": 400, "message": "参数错误"})
|
resp.Code = proto.ParameterError
|
||||||
return
|
resp.Message = "参数解析失败:" + err.Error()
|
||||||
} else {
|
} else {
|
||||||
token := c.Request.Header.Get("token")
|
token := c.Request.Header.Get("token")
|
||||||
if token == "" {
|
if token == "" {
|
||||||
c.JSON(200, gin.H{"code": 401, "message": "token为空"})
|
resp.Code = proto.TokenIsNull //token为空
|
||||||
return
|
} else {
|
||||||
}
|
devices := worker.GetRedisSetMembers(token)
|
||||||
devices := worker.GetRedisSetMembers(token)
|
if len(devices) == 0 {
|
||||||
if len(devices) == 0 {
|
resp.Code = proto.MonitorServerIDIsNull
|
||||||
c.JSON(200, gin.H{"code": 402, "message": "设备为空"})
|
resp.Message = "服务器设备监控为空!"
|
||||||
return
|
} else {
|
||||||
}
|
isExit := false
|
||||||
for _, v := range devices {
|
for _, v := range devices {
|
||||||
if v == req.ID {
|
if v == req.ID {
|
||||||
// 继续处理请求
|
// 继续处理请求
|
||||||
worker.SetRedisWithExpire("monitor_"+req.ID, "1", time.Second*300)
|
//是否是暂停之后第一次上线,如果是则发送邮件通知
|
||||||
c.JSON(200, gin.H{"code": 0, "message": "success"})
|
deviceStatus := worker.GetRedis("monitor_" + req.ID)
|
||||||
return
|
isExist := worker.IsContainKey("monitor_" + req.ID)
|
||||||
|
if deviceStatus == "2" || !isExist {
|
||||||
|
//发送邮件通知
|
||||||
|
title := "设备上线"
|
||||||
|
content := "设备上线\n设备:" + req.ID + "\t状态:" + req.Status + "\t时间:" + time.Now().String()
|
||||||
|
go SendMail(title, content)
|
||||||
|
}
|
||||||
|
worker.SetRedisWithExpire("monitor_"+req.ID, "1", time.Second*300)
|
||||||
|
resp.Code = proto.SuccessCode
|
||||||
|
resp.Message = "success"
|
||||||
|
isExit = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isExit == false {
|
||||||
|
resp.Code = proto.MonitorServerIDNotFound
|
||||||
|
resp.Message = "设备不存在!"
|
||||||
|
log.Println("设备不存在,id:", req.ID, "\ttoken:", token, "\tdevices:", devices)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.JSON(200, gin.H{"code": 402, "message": "设备不存在"})
|
|
||||||
}
|
}
|
||||||
|
c.JSON(http.StatusOK, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFileList(c *gin.Context) {
|
||||||
|
//解析请求参数
|
||||||
|
var req GetFileListReq
|
||||||
|
if err := c.ShouldBind(&req); err == nil {
|
||||||
|
if req.Type == "1" {
|
||||||
|
//按md5查询
|
||||||
|
if req.Md5 == "" {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "md5 is empty", "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file := dao.FindFileByMd5(req.Md5)
|
||||||
|
if file.ID == 0 {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "file not found", "code": proto.FileNotFound, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": file})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DelFile(c *gin.Context) {
|
func DelFile(c *gin.Context) {
|
||||||
|
|
@ -97,12 +219,35 @@ func DelFile(c *gin.Context) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetFile(c *gin.Context) {
|
||||||
|
//先查看是否有权限
|
||||||
|
filename := c.Param("filename")
|
||||||
|
if filename == "" {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "filename is empty", "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//查询文件信息
|
||||||
|
file := dao.FindFileByName(filename)
|
||||||
|
if file.ID == 0 {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "file not found", "code": proto.FileNotFound, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//下载文件
|
||||||
|
if file.NeedAuth == false {
|
||||||
|
c.File(file.FilePath + "/" + file.FileStoreName)
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "file must auth", "data": "file must auth"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func UploadFile(c *gin.Context) {
|
func UploadFile(c *gin.Context) {
|
||||||
//先查看是否有权限
|
//先查看是否有权限
|
||||||
id, _ := c.Get("id")
|
id, _ := c.Get("id")
|
||||||
id1 := int(id.(float64))
|
id1 := int(id.(float64))
|
||||||
//从请求头获取upload_type
|
//从请求头获取upload_type
|
||||||
uploadType := c.PostForm("upload_type")
|
uploadType := c.PostForm("upload_type")
|
||||||
|
authType := c.PostForm("auth_type")
|
||||||
|
md5_ := c.PostForm("md5")
|
||||||
if uploadType == "" {
|
if uploadType == "" {
|
||||||
c.JSON(http.StatusOK, gin.H{"error": "upload_type is empty", "code": proto.ParameterError, "message": "failed"})
|
c.JSON(http.StatusOK, gin.H{"error": "upload_type is empty", "code": proto.ParameterError, "message": "failed"})
|
||||||
return
|
return
|
||||||
|
|
@ -119,6 +264,22 @@ func UploadFile(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, gin.H{"error": "upload file failed", "code": proto.UploadFileFailed, "message": "failed"})
|
c.JSON(http.StatusOK, gin.H{"error": "upload file failed", "code": proto.UploadFileFailed, "message": "failed"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
//计算文件md5值
|
||||||
|
if md5_ == "" {
|
||||||
|
file_, _ := file.Open()
|
||||||
|
md5_ = service.CalculateFileMd5(file_)
|
||||||
|
if md5_ == "" {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "计算文件MD5值失败", "code": proto.UploadFileFailed, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//查询文件是否已存在
|
||||||
|
fileExist := dao.FindFileByMd5(md5_)
|
||||||
|
if fileExist.ID != 0 {
|
||||||
|
fileExist.FilePath = ""
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": fileExist})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
//保存文件
|
//保存文件
|
||||||
filePath, fileStoreName, err := service.SaveFile(c, file, uploadType)
|
filePath, fileStoreName, err := service.SaveFile(c, file, uploadType)
|
||||||
|
|
@ -130,12 +291,19 @@ func UploadFile(c *gin.Context) {
|
||||||
fileSize := int(file.Size)
|
fileSize := int(file.Size)
|
||||||
fileName := file.Filename
|
fileName := file.Filename
|
||||||
fileType := file.Header.Get("file_type")
|
fileType := file.Header.Get("file_type")
|
||||||
fileID := dao.CreateFile(fileStoreName, fileName, fileType, filePath, fileSize, id1)
|
var auth_type_ bool
|
||||||
if fileID == 0 {
|
if authType == "public" || authType == "" {
|
||||||
|
auth_type_ = false
|
||||||
|
} else if authType == "private" {
|
||||||
|
auth_type_ = true
|
||||||
|
}
|
||||||
|
file_record := dao.CreateFile(fileStoreName, fileName, fileType, filePath, md5_, fileSize, id1, auth_type_)
|
||||||
|
if file_record.ID == 0 {
|
||||||
c.JSON(http.StatusOK, gin.H{"error": "save file info failed", "code": proto.SaveFileInfoFailed, "message": "failed"})
|
c.JSON(http.StatusOK, gin.H{"error": "save file info failed", "code": proto.SaveFileInfoFailed, "message": "failed"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": fileID})
|
file_record.FilePath = ""
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": file_record})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,9 +382,14 @@ func GetRedis(c *gin.Context) {
|
||||||
//解析请求参数
|
//解析请求参数
|
||||||
var req SetRedisReq
|
var req SetRedisReq
|
||||||
if err := c.ShouldBind(&req); err == nil {
|
if err := c.ShouldBind(&req); err == nil {
|
||||||
code, message := service.GetToolRedis(req.Key)
|
if req.Option == "one" {
|
||||||
req.Value = message
|
code, message := service.GetToolRedis(req.Key)
|
||||||
c.JSON(http.StatusOK, gin.H{"code": code, "message": message, "data": req})
|
req.Value = message
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": code, "message": message, "data": req})
|
||||||
|
} else if req.Option == "all" {
|
||||||
|
code, message, data := service.GetAllRedis()
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": code, "message": message, "data": data})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
|
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
|
||||||
return
|
return
|
||||||
|
|
@ -233,7 +406,7 @@ func ScanDeviceStatus() {
|
||||||
for _, v := range devices {
|
for _, v := range devices {
|
||||||
c := worker.IsContainKey("monitor_" + v)
|
c := worker.IsContainKey("monitor_" + v)
|
||||||
if c == false {
|
if c == false {
|
||||||
worker.SetRedisWithExpire("monitor_"+v, "1", time.Hour*24)
|
worker.SetRedisWithExpire("monitor_"+v, "2", time.Hour*24)
|
||||||
offline += v + ","
|
offline += v + ","
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -272,3 +445,36 @@ func SendMail(title, content string) {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SendMailTool(c *gin.Context) {
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
id1 := int(id.(float64))
|
||||||
|
|
||||||
|
var req SendMailReq
|
||||||
|
if err := c.ShouldBind(&req); err == nil {
|
||||||
|
user := dao.FindUserByUserID(id1)
|
||||||
|
if user.ID == 0 {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "user not found", "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//目标邮箱地址是否合法
|
||||||
|
if !service.CheckEmail(req.To) {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "email address is invalid", "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if req.Title == "" || req.Content == "" {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "title or content is empty", "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//发送邮件
|
||||||
|
if user.Role == "admin" {
|
||||||
|
go service.SendEmail(req.To, req.Title, req.Content)
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success", "data": "mail will be sent"})
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "no send mail permission", "code": proto.PermissionDenied, "message": "failed"})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
173
handler/user.go
173
handler/user.go
|
|
@ -26,6 +26,9 @@ func SetUpUserGroup(router *gin.Engine) {
|
||||||
userGroup.POST("/search", SearchHandler)
|
userGroup.POST("/search", SearchHandler)
|
||||||
userGroup.POST("/info", GetUserInfo)
|
userGroup.POST("/info", GetUserInfo)
|
||||||
userGroup.POST("/update", UpdateUserInfo)
|
userGroup.POST("/update", UpdateUserInfo)
|
||||||
|
userGroup.POST("/sync", GetSyncUserInfo)
|
||||||
|
userGroup.POST("/delete", DeleteUser)
|
||||||
|
userGroup.POST("/reset", ResetPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RLReq struct {
|
type RLReq struct {
|
||||||
|
|
@ -77,6 +80,23 @@ func GetUserInfo(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DeleteUser(c *gin.Context) {
|
||||||
|
var req GetUserInfoReq
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
user_id := int(id.(float64))
|
||||||
|
if err := c.ShouldBind(&req); err == nil {
|
||||||
|
res := service.DeleteUserService(req.ID, user_id)
|
||||||
|
if res != 0 {
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": res})
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "failed", "data": res})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.ParameterError, "message": err, "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func UpdateUserInfo(c *gin.Context) {
|
func UpdateUserInfo(c *gin.Context) {
|
||||||
var req_data proto.UpdateUserInfoReq
|
var req_data proto.UpdateUserInfoReq
|
||||||
id, _ := c.Get("id")
|
id, _ := c.Get("id")
|
||||||
|
|
@ -350,3 +370,156 @@ func registerHandler(c *gin.Context) {
|
||||||
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": data})
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": data})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetSyncUserInfo(c *gin.Context) {
|
||||||
|
var req_data proto.SyncUserReq
|
||||||
|
if err := c.ShouldBind(&req_data); err == nil {
|
||||||
|
if req_data.Token == "" {
|
||||||
|
c.JSON(200, gin.H{"code": proto.ParameterError, "message": "error", "data": "token is empty"})
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
if worker.IsContainSet("super_permission_tokens", req_data.Token) {
|
||||||
|
if proto.Config.SERVER_USER_TYPE == "master" {
|
||||||
|
if req_data.Types == 1 { //1为全量同步
|
||||||
|
add_users := dao.GetAllUser()
|
||||||
|
resp := dao.UserSyncResp{}
|
||||||
|
resp.Add = add_users
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": resp})
|
||||||
|
} else if req_data.Types == 2 { //2为增量同步
|
||||||
|
if req_data.Device == "" || worker.IsContainSet("sync_devices_ids", req_data.Device) == false {
|
||||||
|
c.JSON(200, gin.H{"code": proto.ParameterError, "message": "error", "data": "device is empty or not exist"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := service.GetUserSyncData(req_data.Device)
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": res})
|
||||||
|
} else if req_data.Types == 3 { //3为确认同步数据
|
||||||
|
res := service.ConfirmSyncUserData(req_data.Device, req_data.Confirm)
|
||||||
|
if res == nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "success"})
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "failed:" + res.Error(), "data": "failed"})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.ParameterError, "message": "type is error", "data": dao.UserSyncResp{}})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.NoPermission, "message": "no permission,server is not master", "data": proto.UserSync{}})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.NoPermission, "message": "error", "data": "no permission"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "error"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResetPasswordReq struct {
|
||||||
|
Email string `json:"email" form:"email"`
|
||||||
|
OldPassword string `json:"old_password" form:"old_password"`
|
||||||
|
NewPassword string `json:"new_password" form:"new_password"`
|
||||||
|
Type int `json:"type" form:"type"` //0获取验证码,2为邮箱验证码重置密码,1为旧密码重置密码
|
||||||
|
Code string `json:"code" form:"code"` //验证码
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResetPassword(c *gin.Context) {
|
||||||
|
var req_data ResetPasswordReq
|
||||||
|
if err := c.ShouldBind(&req_data); err == nil {
|
||||||
|
if req_data.Type == 0 {
|
||||||
|
//获取验证码
|
||||||
|
//查看是否存在该邮箱
|
||||||
|
user := dao.FindUserByEmail(req_data.Email)
|
||||||
|
if user.ID == 0 {
|
||||||
|
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "邮箱不存在", "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if worker.IsContainKey("reset_password_" + req_data.Email) {
|
||||||
|
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "验证码已发送,请5分钟后再试", "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//随机字符串验证码大写
|
||||||
|
code := worker.GetRandomString(6)
|
||||||
|
worker.SetRedisWithExpire("reset_password_"+req_data.Email, code, time.Minute*5) //设置5分钟过期`
|
||||||
|
//发送邮件
|
||||||
|
service.SendEmail(req_data.Email, "大学生学业作品AI生成工具开发重置密码", "验证码:"+code+" ,请在5分钟内使用!")
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "2"})
|
||||||
|
return
|
||||||
|
} else if req_data.Type == 1 {
|
||||||
|
//旧密码重置密码
|
||||||
|
if len(req_data.OldPassword) != 32 {
|
||||||
|
hasher := md5.New()
|
||||||
|
hasher.Write([]byte(req_data.OldPassword)) // 生成密码的 MD5 散列值
|
||||||
|
req_data.OldPassword = hex.EncodeToString(hasher.Sum(nil)) // 生成密码的 MD5 散列值
|
||||||
|
}
|
||||||
|
if len(req_data.NewPassword) != 32 {
|
||||||
|
hasher := md5.New()
|
||||||
|
hasher.Write([]byte(req_data.NewPassword)) // 生成密码的 MD5 散列值
|
||||||
|
req_data.NewPassword = hex.EncodeToString(hasher.Sum(nil)) // 生成密码的 MD5 散列值
|
||||||
|
}
|
||||||
|
user := dao.FindUserByEmail(req_data.Email)
|
||||||
|
if user.ID == 0 {
|
||||||
|
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "邮箱不存在", "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if user.Password != req_data.OldPassword {
|
||||||
|
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "旧密码错误", "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if user.Password == req_data.NewPassword {
|
||||||
|
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "新旧密码相同", "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dao.UpdateUserByID(int(user.ID), user.Name, req_data.NewPassword, user.Email)
|
||||||
|
var resp proto.ResponseOAuth
|
||||||
|
token, err2 := service.CreateTokenAndSave(user)
|
||||||
|
if err2 != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "new token error", "data": resp})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp.Token = token
|
||||||
|
resp.ID = user.ID
|
||||||
|
resp.Name = user.Name
|
||||||
|
resp.Email = user.Email
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": resp})
|
||||||
|
} else if req_data.Type == 2 {
|
||||||
|
//邮箱重置密码
|
||||||
|
if len(req_data.NewPassword) != 32 {
|
||||||
|
hasher := md5.New()
|
||||||
|
hasher.Write([]byte(req_data.NewPassword)) // 生成密码的 MD5 散列值
|
||||||
|
req_data.NewPassword = hex.EncodeToString(hasher.Sum(nil)) // 生成密码的 MD5 散列值
|
||||||
|
}
|
||||||
|
user := dao.FindUserByEmail(req_data.Email)
|
||||||
|
if user.ID == 0 {
|
||||||
|
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "邮箱不存在", "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
code := worker.GetRedis("reset_password_" + req_data.Email)
|
||||||
|
if code != req_data.Code {
|
||||||
|
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "验证码错误", "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dao.UpdateUserByID(int(user.ID), user.Name, req_data.NewPassword, user.Email)
|
||||||
|
token, err2 := service.CreateTokenAndSave(user)
|
||||||
|
if err2 != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "new token error", "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var resp proto.ResponseOAuth
|
||||||
|
resp.Token = token
|
||||||
|
resp.ID = user.ID
|
||||||
|
resp.Name = user.Name
|
||||||
|
resp.Email = user.Email
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": resp})
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "type error", "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.ParameterError, "message": err, "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import (
|
||||||
|
|
||||||
// video获取视频列表请求
|
// video获取视频列表请求
|
||||||
type gvlReq struct {
|
type gvlReq struct {
|
||||||
|
ID int `json:"id" form:"id"`
|
||||||
StartTime int64 `json:"begin" form:"begin"`
|
StartTime int64 `json:"begin" form:"begin"`
|
||||||
EndTime int64 `json:"end" form:"end"`
|
EndTime int64 `json:"end" form:"end"`
|
||||||
IP string `json:"ip" form:"ip"`
|
IP string `json:"ip" form:"ip"`
|
||||||
|
|
@ -59,12 +60,13 @@ type videoPReq struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type VideoDelReq struct {
|
type VideoDelReq struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id" form:"id"`
|
||||||
|
Type string `json:"type" form:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// video延迟视频请求
|
// video延迟视频请求
|
||||||
type delayReq struct {
|
type delayReq struct {
|
||||||
ID int `form:"id"`
|
ID int `json:"id" form:"id"`
|
||||||
Option string `form:"option"`
|
Option string `form:"option"`
|
||||||
AuthId int `form:"userId"`
|
AuthId int `form:"userId"`
|
||||||
IP string `form:"ip"`
|
IP string `form:"ip"`
|
||||||
|
|
@ -164,7 +166,7 @@ func GetVideoList(c *gin.Context) {
|
||||||
tm1 = ""
|
tm1 = ""
|
||||||
tm2 = ""
|
tm2 = ""
|
||||||
}
|
}
|
||||||
videos := service.GetVideoList(int(id.(float64)), tm1, tm2, gvl_req.Hour)
|
videos := service.GetVideoList(int(id.(float64)), gvl_req.ID, tm1, tm2, gvl_req.Hour)
|
||||||
c.JSON(http.StatusOK, gin.H{"data": videos, "code": proto.SuccessCode, "message": "success"})
|
c.JSON(http.StatusOK, gin.H{"data": videos, "code": proto.SuccessCode, "message": "success"})
|
||||||
} else {
|
} else {
|
||||||
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
|
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
|
||||||
|
|
@ -192,7 +194,7 @@ func DelayVideo(c *gin.Context) {
|
||||||
} else {
|
} else {
|
||||||
data := map[string]interface{}{"auth_id": int(id.(float64)), "method": "delay", "delay_time": time.Now().Format("2006-01-02 15:04:05"), "delay_day": delay_req.Day, "option": delay_req.Option, "id": delay_req.ID}
|
data := map[string]interface{}{"auth_id": int(id.(float64)), "method": "delay", "delay_time": time.Now().Format("2006-01-02 15:04:05"), "delay_day": delay_req.Day, "option": delay_req.Option, "id": delay_req.ID}
|
||||||
str, _ := json.Marshal(data)
|
str, _ := json.Marshal(data)
|
||||||
worker.PushRedisList(user.(string)+"-"+strconv.Itoa(int(id.(float64)))+"-option", string(str))
|
service.SetVideoOption(user.(string)+"-"+strconv.Itoa(int(id.(float64)))+"-option", string(str))
|
||||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "data": "延迟成功,影响记录:" + strconv.Itoa(cnt), "message": "success cnt:" + strconv.Itoa(cnt)})
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "data": "延迟成功,影响记录:" + strconv.Itoa(cnt), "message": "success cnt:" + strconv.Itoa(cnt)})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -203,34 +205,30 @@ func DelayVideo(c *gin.Context) {
|
||||||
func DeleteVideo(c *gin.Context) {
|
func DeleteVideo(c *gin.Context) {
|
||||||
var video_req VideoDelReq
|
var video_req VideoDelReq
|
||||||
id, _ := c.Get("id")
|
id, _ := c.Get("id")
|
||||||
user, _ := c.Get("username")
|
|
||||||
if err := c.ShouldBind(&video_req); err == nil {
|
if err := c.ShouldBind(&video_req); err == nil {
|
||||||
res := service.DeleteVideo(video_req.ID, int(id.(float64)))
|
res := service.DeleteVideo(video_req.ID, int(id.(float64)), video_req.Type)
|
||||||
if res != 0 {
|
if res != 0 {
|
||||||
data := map[string]interface{}{"id": video_req.ID, "auth_id": int(id.(float64)), "delete_time": time.Now().Format("2006-01-02 15:04:05"), "method": "delete"}
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "msg": "success", "data": "delete video success"})
|
||||||
str, _ := json.Marshal(data)
|
|
||||||
worker.PushRedisList(user.(string)+"-"+strconv.Itoa(int(id.(float64)))+"-option", string(str))
|
|
||||||
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
|
||||||
} else {
|
} else {
|
||||||
c.JSON(http.StatusOK, gin.H{"code": proto.ParameterError, "message": "failed"})
|
c.JSON(http.StatusOK, gin.H{"code": proto.ParameterError, "msg": "failed", "data": "delete video failed"})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "failed"})
|
c.JSON(http.StatusOK, gin.H{"error": err.Error(), "code": proto.ParameterError, "msg": err, "data": "failed"})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func QuashOption(c *gin.Context) {
|
func QuashOption(c *gin.Context) {
|
||||||
id, _ := c.Get("id")
|
id, _ := c.Get("id")
|
||||||
user, _ := c.Get("username")
|
id1 := int(id.(float64))
|
||||||
res := worker.PopRedisList(user.(string) + "-" + strconv.Itoa(int(id.(float64))) + "-option")
|
res := worker.PopRedisList("user-" + strconv.Itoa(int(id.(float64))) + "-option")
|
||||||
if res != "" {
|
if res != "" {
|
||||||
var retrievedData map[string]interface{}
|
var retrievedData map[string]interface{}
|
||||||
err2 := json.Unmarshal([]byte(res), &retrievedData)
|
err2 := json.Unmarshal([]byte(res), &retrievedData)
|
||||||
if err2 == nil {
|
if err2 == nil {
|
||||||
code, msg := service.QuashVideo(int(id.(float64)), retrievedData)
|
code, msg := service.QuashVideo(id1, retrievedData)
|
||||||
c.JSON(http.StatusOK, gin.H{"code": code, "message": msg, "data": msg})
|
c.JSON(http.StatusOK, gin.H{"code": code, "message": msg, "data": msg})
|
||||||
} else {
|
} else {
|
||||||
worker.PushRedisList(user.(string)+"-"+strconv.Itoa(int(id.(float64)))+"-option", res) //未操作成功重新添加到队列
|
worker.PushRedisList("user-"+strconv.Itoa(int(id.(float64)))+"-option", res) //未操作成功重新添加到队列
|
||||||
c.JSON(http.StatusOK, gin.H{"code": proto.ParameterError, "message": err2, "data": "json解析错误"})
|
c.JSON(http.StatusOK, gin.H{"code": proto.ParameterError, "message": err2, "data": "json解析错误"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
129
main.go
129
main.go
|
|
@ -8,11 +8,14 @@ import (
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"videoplayer/dao"
|
"videoplayer/dao"
|
||||||
"videoplayer/handler"
|
"videoplayer/handler"
|
||||||
"videoplayer/proto"
|
"videoplayer/proto"
|
||||||
|
"videoplayer/service"
|
||||||
"videoplayer/worker"
|
"videoplayer/worker"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -28,13 +31,15 @@ func main() {
|
||||||
panic("failed to connect redis:" + err.Error())
|
panic("failed to connect redis:" + err.Error())
|
||||||
}
|
}
|
||||||
r.Use(handler.CrosHandler())
|
r.Use(handler.CrosHandler())
|
||||||
r.Use(JWTAuthMiddleware()) // 使用 JWT 认证中间件
|
r.Use(JWTAuthMiddleware()) // 使用 JWT 认证中间件
|
||||||
handler.SetUpVideoGroup(r) // Video
|
handler.SetUpVideoGroup(r) // Video
|
||||||
handler.SetUpUserGroup(r) // User
|
//handler.SetUpUserGroup(r) // User
|
||||||
handler.SetUpDeviceGroup(r) // Device
|
handler.SetUpDeviceGroup(r) // Device
|
||||||
handler.SetUpIMGroup(r) // IM
|
handler.SetUpIMGroup(r) // IM
|
||||||
handler.SetUpCIDGroup(r) // CID,持续集成、部署
|
handler.SetUpCIDGroup(r) // CID,持续集成、部署
|
||||||
handler.SetUpToolGroup(r) // Tool
|
handler.SetUpToolGroup(r) // Tool
|
||||||
|
handler.SetUpFileGroup(r) // File
|
||||||
|
handler.SetUpShellGroup(r) // Shell
|
||||||
defer dao.Close()
|
defer dao.Close()
|
||||||
defer worker.CloseRedis()
|
defer worker.CloseRedis()
|
||||||
//定时任务
|
//定时任务
|
||||||
|
|
@ -100,13 +105,16 @@ func JWTAuthMiddleware() gin.HandlerFunc {
|
||||||
if tokenString == "" {
|
if tokenString == "" {
|
||||||
tokenString = c.Query("token")
|
tokenString = c.Query("token")
|
||||||
}
|
}
|
||||||
|
|
||||||
//如果请求为login或register,则不需要验证token
|
//如果请求为login或register,则不需要验证token
|
||||||
for k, _ := range proto.Url_map {
|
//for k, _ := range proto.Url_map {
|
||||||
if strings.Contains(c.Request.URL.Path, k) {
|
// if strings.Contains(c.Request.URL.Path, k) {
|
||||||
c.Next()
|
// c.Next()
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
//}
|
||||||
|
if proto.Url_map[c.Request.URL.Path] == true { //查看是否在不需要token的url中
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if tokenString == "" {
|
if tokenString == "" {
|
||||||
//c.AbortWithStatus(200)
|
//c.AbortWithStatus(200)
|
||||||
|
|
@ -120,41 +128,39 @@ func JWTAuthMiddleware() gin.HandlerFunc {
|
||||||
if proto.Config.TOKEN_USE_REDIS {
|
if proto.Config.TOKEN_USE_REDIS {
|
||||||
redisToken := worker.GetRedis(tokenString)
|
redisToken := worker.GetRedis(tokenString)
|
||||||
if redisToken == "" {
|
if redisToken == "" {
|
||||||
c.AbortWithStatus(200)
|
c.AbortWithStatusJSON(http.StatusOK, gin.H{"message": "NOT_LOGIN", "error": "server token is empty", "code": proto.TokenIsNull})
|
||||||
c.JSON(200, gin.H{
|
|
||||||
"message": "NOT_LOGIN",
|
|
||||||
"error": "server token is empty",
|
|
||||||
"code": proto.TokenIsNull,
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//查看token是否在超级token中
|
//查看token是否在超级token中
|
||||||
if worker.IsContainSet("super_permission_tokens", tokenString) {
|
if worker.IsContainSet("super_permission_tokens", tokenString) {
|
||||||
s_id := c.Request.Header.Get("super_id")
|
sId := c.Request.Header.Get("super_id")
|
||||||
if s_id == "" {
|
if sId == "" {
|
||||||
c.AbortWithStatus(200)
|
sId = c.Query("super_id")
|
||||||
c.JSON(200, gin.H{
|
}
|
||||||
"message": "NOT_LOGIN",
|
if sId == "" {
|
||||||
"error": "super_id is empty",
|
c.AbortWithStatusJSON(http.StatusOK, gin.H{"message": "unauthorized", "error": "super_id is empty", "code": proto.TokenIsNull})
|
||||||
"code": proto.TokenIsNull,
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Set("id", s_id)
|
id, _ := strconv.Atoi(sId)
|
||||||
|
idFloat64 := float64(id)
|
||||||
|
//查看s_id类型
|
||||||
|
c.Set("id", idFloat64)
|
||||||
c.Next()
|
c.Next()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proto.SigningKeyRWLock.RLock() //加读锁
|
||||||
// 使用加密secret 解析 JWT 令牌
|
// 使用加密secret 解析 JWT 令牌
|
||||||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||||
return proto.SigningKey, nil
|
return proto.SigningKey, nil
|
||||||
})
|
})
|
||||||
|
proto.SigningKeyRWLock.RUnlock()
|
||||||
|
|
||||||
// 验证令牌
|
// 验证令牌
|
||||||
if err != nil || !token.Valid {
|
if err != nil || !token.Valid {
|
||||||
c.AbortWithStatus(200)
|
c.AbortWithStatusJSON(http.StatusOK, gin.H{
|
||||||
c.JSON(200, gin.H{
|
|
||||||
"message": "NOT_LOGIN",
|
"message": "NOT_LOGIN",
|
||||||
"error": "Invalid token",
|
"error": "Invalid token",
|
||||||
"code": proto.TokenExpired,
|
"code": proto.TokenExpired,
|
||||||
|
|
@ -167,8 +173,7 @@ func JWTAuthMiddleware() gin.HandlerFunc {
|
||||||
c.Set("username", token.Claims.(jwt.MapClaims)["username"])
|
c.Set("username", token.Claims.(jwt.MapClaims)["username"])
|
||||||
|
|
||||||
if UserFuncIntercept(int(token.Claims.(jwt.MapClaims)["id"].(float64)), c.Request.URL.Path) {
|
if UserFuncIntercept(int(token.Claims.(jwt.MapClaims)["id"].(float64)), c.Request.URL.Path) {
|
||||||
c.AbortWithStatus(200)
|
c.AbortWithStatusJSON(http.StatusOK, gin.H{
|
||||||
c.JSON(200, gin.H{
|
|
||||||
"message": "no function permission",
|
"message": "no function permission",
|
||||||
"error": "no permission",
|
"error": "no permission",
|
||||||
"code": proto.NoPermission,
|
"code": proto.NoPermission,
|
||||||
|
|
@ -190,10 +195,20 @@ func myTask() {
|
||||||
}
|
}
|
||||||
//其它定时任务-通用
|
//其它定时任务-通用
|
||||||
RunGeneralCron()
|
RunGeneralCron()
|
||||||
|
service.ShellWillRunFromServer()
|
||||||
|
service.SyncTokenSecretFromUserCenter()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadConfigToSetSystem() {
|
func ReadConfigToSetSystem() {
|
||||||
|
//将当前配置文件的信息写入redis,用于程序运行时排查
|
||||||
|
config_json, c_err := json.Marshal(proto.Config)
|
||||||
|
if c_err != nil {
|
||||||
|
fmt.Println("ReadConfigToSetSystem Error encoding config,err :", c_err)
|
||||||
|
} else {
|
||||||
|
worker.SetRedis("system_config_info", string(config_json))
|
||||||
|
}
|
||||||
|
|
||||||
//redis添加通用定时任务
|
//redis添加通用定时任务
|
||||||
key := "cron_info"
|
key := "cron_info"
|
||||||
//日志清理
|
//日志清理
|
||||||
|
|
@ -222,8 +237,35 @@ func ReadConfigToSetSystem() {
|
||||||
logClean.Every = 86400
|
logClean.Every = 86400
|
||||||
cron_infos = append(cron_infos, logClean)
|
cron_infos = append(cron_infos, logClean)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_exist := false
|
||||||
|
user_sync_id := -1 //用户同步任务索引
|
||||||
|
for i, v := range cron_infos {
|
||||||
|
if v.Type == 2 {
|
||||||
|
is_exist = true
|
||||||
|
if proto.Config.USER_SYNC_TIME != v.Every {
|
||||||
|
v.Every = proto.Config.USER_SYNC_TIME
|
||||||
|
v.Curr = proto.Config.USER_SYNC_TIME
|
||||||
|
}
|
||||||
|
user_sync_id = i
|
||||||
|
cron_infos[i] = v
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if proto.Config.SERVER_USER_TYPE == "slave" {
|
||||||
|
if proto.Config.USER_SYNC_TIME > 0 && !is_exist {
|
||||||
|
var userSync proto.CronInfo
|
||||||
|
userSync.Type = 2
|
||||||
|
userSync.Info = "user"
|
||||||
|
userSync.Curr = proto.Config.USER_SYNC_TIME
|
||||||
|
userSync.Every = proto.Config.USER_SYNC_TIME
|
||||||
|
cron_infos = append(cron_infos, userSync)
|
||||||
|
} else if user_sync_id != -1 {
|
||||||
|
cron_infos = append(cron_infos[:user_sync_id], cron_infos[user_sync_id+1:]...) //删除
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if proto.Config.LOG_SAVE_DAYS > 0 {
|
if proto.Config.LOG_SAVE_DAYS > 0 {
|
||||||
var logClean proto.CronInfo
|
var logClean proto.CronInfo
|
||||||
|
|
@ -233,6 +275,14 @@ func ReadConfigToSetSystem() {
|
||||||
logClean.Every = 86400
|
logClean.Every = 86400
|
||||||
cron_infos = append(cron_infos, logClean)
|
cron_infos = append(cron_infos, logClean)
|
||||||
}
|
}
|
||||||
|
if proto.Config.SERVER_USER_TYPE == "slave" && proto.Config.USER_SYNC_TIME > 0 {
|
||||||
|
var userSync proto.CronInfo
|
||||||
|
userSync.Type = 2
|
||||||
|
userSync.Info = "user"
|
||||||
|
userSync.Curr = proto.Config.USER_SYNC_TIME
|
||||||
|
userSync.Every = proto.Config.USER_SYNC_TIME
|
||||||
|
cron_infos = append(cron_infos, userSync)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//存入redis
|
//存入redis
|
||||||
json_data, err := json.Marshal(cron_infos)
|
json_data, err := json.Marshal(cron_infos)
|
||||||
|
|
@ -254,7 +304,7 @@ func RunGeneralCron() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("RunGeneralCron Error decoding config,key value is :", res)
|
fmt.Println("RunGeneralCron Error decoding config,key value is :", res)
|
||||||
}
|
}
|
||||||
for _, v := range cron_infos {
|
for i, v := range cron_infos {
|
||||||
//1:日志清理,其他待定
|
//1:日志清理,其他待定
|
||||||
if v.Type == 1 {
|
if v.Type == 1 {
|
||||||
//日志清理
|
//日志清理
|
||||||
|
|
@ -265,6 +315,22 @@ func RunGeneralCron() {
|
||||||
} else {
|
} else {
|
||||||
v.Curr -= 10
|
v.Curr -= 10
|
||||||
}
|
}
|
||||||
|
cron_infos[i] = v
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//2 从服务器同步数据
|
||||||
|
if v.Type == 2 {
|
||||||
|
if v.Curr <= 0 {
|
||||||
|
//执行从服务器同步数据
|
||||||
|
if proto.Config.SERVER_USER_TYPE == "slave" && v.Info == "user" {
|
||||||
|
go service.UserSyncDataFromMaster()
|
||||||
|
}
|
||||||
|
v.Curr = v.Every
|
||||||
|
} else {
|
||||||
|
v.Curr -= 10
|
||||||
|
}
|
||||||
|
cron_infos[i] = v
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//存入redis
|
//存入redis
|
||||||
|
|
@ -274,14 +340,13 @@ func RunGeneralCron() {
|
||||||
} else {
|
} else {
|
||||||
worker.SetRedis(key, string(json_data))
|
worker.SetRedis(key, string(json_data))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用户功能拦截,返回true表示拦截,false表示不拦截
|
// 用户功能拦截,返回true表示拦截,false表示不拦截
|
||||||
func UserFuncIntercept(id int, url string) bool {
|
func UserFuncIntercept(id int, url string) bool {
|
||||||
//先查看是否有权限
|
//先查看是否有权限
|
||||||
user := dao.FindUserByUserID(id)
|
user := service.GetUserByIDFromUserCenter(id)
|
||||||
//如果用户有权限,则不拦截
|
//如果用户有权限,则不拦截
|
||||||
for k, v := range proto.Per_menu_map {
|
for k, v := range proto.Per_menu_map {
|
||||||
if strings.Contains(url, k) {
|
if strings.Contains(url, k) {
|
||||||
|
|
|
||||||
113
proto/conf.go
113
proto/conf.go
|
|
@ -4,13 +4,22 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Config ConfigStruct
|
var Config ConfigStruct
|
||||||
var SigningKey = []byte{}
|
var SigningKey = []byte{}
|
||||||
var Url_map = map[string]bool{"/login": true, "/register": true, "/uuid": true, "/gqr": true, "/cid/callback": true, "/tool/monitor": true} // 不需要token验证的url
|
var Url_map = map[string]bool{"/login": true, "/register": true, "/uuid": true, "/gqr": true, "/cid/callback": true, "/tool/monitor": true, "/user/sync": true, "/tool/file/": true, "/user/reset": true} // 不需要token验证的url
|
||||||
var Per_menu_map = map[string]int{"/video/": 1, "/device/": 2, "/cid/": 3}
|
var Per_menu_map = map[string]int{"/video/": 1, "/device/": 2, "/cid/": 3}
|
||||||
|
var File_Type = map[string]int{"im": 1, "avatar": 2, "file": 3, "config": 4} // 文件类型
|
||||||
|
|
||||||
|
// 配置读写锁
|
||||||
|
var ConfigRWLock = &sync.RWMutex{}
|
||||||
|
var SigningKeyRWLock = &sync.RWMutex{}
|
||||||
|
|
||||||
|
var SyncSecretReqLog int64
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MYSQL_USER = "video_t2"
|
MYSQL_USER = "video_t2"
|
||||||
|
|
@ -63,24 +72,75 @@ type User struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigStruct struct {
|
type ConfigStruct struct {
|
||||||
DB int `json:"db"` // 0: mysql, 1: pg
|
DB int `json:"db"` // 0: mysql, 1: pg
|
||||||
MYSQL_DSN string `json:"mysql_dsn"`
|
MYSQL_DSN string `json:"mysql_dsn"`
|
||||||
PG_DSN string `json:"pg_dsn"`
|
PG_DSN string `json:"pg_dsn"`
|
||||||
REDIS_ADDR string `json:"redis_addr"`
|
REDIS_ADDR string `json:"redis_addr"`
|
||||||
TOKEN_USE_REDIS bool `json:"token_use_redis"`
|
TOKEN_USE_REDIS bool `json:"token_use_redis"`
|
||||||
REDIS_User_PW bool `json:"redis_user_pw"` // 是否使用密码
|
REDIS_User_PW bool `json:"redis_user_pw"` // 是否使用密码
|
||||||
REDIS_PASSWORD string `json:"redis_password"`
|
REDIS_PASSWORD string `json:"redis_password"`
|
||||||
REDIS_DB int `json:"redis_db"`
|
REDIS_DB int `json:"redis_db"`
|
||||||
TOKEN_SECRET string `json:"token_secret"`
|
TOKEN_SECRET string `json:"token_secret"`
|
||||||
CID_BASE_DIR string `json:"cid_base_dir"`
|
CID_BASE_DIR string `json:"cid_base_dir"`
|
||||||
FILE_BASE_DIR string `json:"file_base_dir"`
|
FILE_BASE_DIR string `json:"file_base_dir"`
|
||||||
MONITOR bool `json:"monitor"` // 状态监控及邮件通知
|
MONITOR bool `json:"monitor"` // 状态监控及邮件通知
|
||||||
SERVER_PORT string `json:"server_port"` // 服务端口
|
SERVER_SQL_LOG bool `json:"server_sql_log"` // 服务器sql日志
|
||||||
LOG_SAVE_DAYS int `json:"log_save_days"` // 日志保存天数,-1表示不保存,0表示永久保存
|
SERVER_PORT string `json:"server_port"` // 服务端口
|
||||||
|
LOG_SAVE_DAYS int `json:"log_save_days"` // 日志保存天数,-1表示不保存,0表示永久保存
|
||||||
|
SERVER_USER_TYPE string `json:"user_type"` // 服务器用户类型,master: 主服务器,slave: 从服务器,从服务器会定时同步数据
|
||||||
|
MASTER_SERVER_DOMAIN string `json:"master_server_domain"` // 主服务器域名
|
||||||
|
USER_SYNC_TIME int `json:"user_sync_time"` // 用户数据同步时间,单位秒
|
||||||
|
SERVER_NAME string `json:"server_name"` // 服务器名称,用于区分不同服务器
|
||||||
|
MONITOR_SERVER_TOKEN string `json:"monitor_server_token"` // 监控服务器token,用于状态监控及邮件通知
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteConfigToFile() {
|
||||||
|
//系统是linux、macos还是windows
|
||||||
|
var configPath string
|
||||||
|
if os.Getenv("OS") == "Windows_NT" {
|
||||||
|
configPath = "D:/Code/videoplayer/vp.conf"
|
||||||
|
} else if os.Getenv("OS") == "linux" {
|
||||||
|
//文件地址/home/saw-ai/saw-ai.conf
|
||||||
|
configPath = "/home/videoplayer/vp.conf"
|
||||||
|
} else {
|
||||||
|
configPath = "/home/videoplayer/vp.conf"
|
||||||
|
}
|
||||||
|
configData, err := json.MarshalIndent(Config, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
log.Println("WriteConfigToFile json marshal error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = os.WriteFile(configPath, configData, 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("WriteConfigToFile write file error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Println("WriteConfigToFile write config to file success")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 读取配置文件
|
// 读取配置文件
|
||||||
func ReadConfig(path string) error {
|
func ReadConfig(path string) error {
|
||||||
|
//查看配置文件是否存在,不存在则创建
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Config file not found!")
|
||||||
|
//创建默认配置
|
||||||
|
DefaultConfig()
|
||||||
|
//写入json文件
|
||||||
|
file, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error creating config file")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
encoder := json.NewEncoder(file)
|
||||||
|
err = encoder.Encode(&Config)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error encoding config")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
//读json文件
|
//读json文件
|
||||||
file, err := os.Open(path)
|
file, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -100,3 +160,26 @@ func ReadConfig(path string) error {
|
||||||
SigningKey = []byte(Config.TOKEN_SECRET)
|
SigningKey = []byte(Config.TOKEN_SECRET)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 默认配置
|
||||||
|
func DefaultConfig() {
|
||||||
|
Config.DB = 2
|
||||||
|
Config.MYSQL_DSN = MYSQL_DSN
|
||||||
|
Config.PG_DSN = ""
|
||||||
|
Config.REDIS_ADDR = REDIS_ADDR
|
||||||
|
Config.TOKEN_USE_REDIS = false
|
||||||
|
Config.REDIS_User_PW = false
|
||||||
|
Config.REDIS_PASSWORD = REDIS_PASSWORD
|
||||||
|
Config.REDIS_DB = REIDS_DB
|
||||||
|
Config.TOKEN_SECRET = TOKEN_SECRET
|
||||||
|
Config.CID_BASE_DIR = CID_BASE_DIR
|
||||||
|
Config.FILE_BASE_DIR = FILE_BASE_DIR
|
||||||
|
Config.MONITOR = false
|
||||||
|
Config.SERVER_SQL_LOG = false
|
||||||
|
Config.SERVER_PORT = "8083"
|
||||||
|
Config.LOG_SAVE_DAYS = 7
|
||||||
|
Config.SERVER_USER_TYPE = "master"
|
||||||
|
Config.MASTER_SERVER_DOMAIN = ""
|
||||||
|
Config.USER_SYNC_TIME = 86400
|
||||||
|
Config.SERVER_NAME = "default"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type FileUploadReq struct {
|
||||||
|
UploadType string `json:"upload_type" form:"upload_type" binding:"required"`
|
||||||
|
AuthType string `json:"auth_type" form:"auth_type"`
|
||||||
|
Md5 string `json:"md5" form:"md5"` //文件md5值
|
||||||
|
Type string `json:"type" form:"type"` //类型,im,avatar,file,config,config为系统文件
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigFileReq struct {
|
||||||
|
ID int `json:"id" form:"id"`
|
||||||
|
Type string `json:"type" form:"type"` //查询类型,one,all
|
||||||
|
DelFile bool `json:"del_file"` //删除文件
|
||||||
|
FileName string `json:"file_name" form:"file_name"`
|
||||||
|
FilePath string `json:"file_path" form:"file_path"`
|
||||||
|
Content string `json:"content" form:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddConfigFileReq struct {
|
||||||
|
FileName string `json:"file_name" form:"file_name" required:"true"`
|
||||||
|
FilePath string `json:"file_path" form:"file_path" required:"true"`
|
||||||
|
}
|
||||||
|
type SearchOneConfigFileResp struct {
|
||||||
|
ID uint `json:"id" form:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at" form:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at" form:"updated_at"`
|
||||||
|
FileName string `json:"file_name" form:"file_name"`
|
||||||
|
FilePath string `json:"file_path" form:"file_path"`
|
||||||
|
Content string `json:"content" form:"content"`
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package proto
|
||||||
|
|
||||||
|
type GeneralResp struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data any `json:"data"`
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package proto
|
||||||
|
|
||||||
|
type GetMonitorDeviceStatus struct {
|
||||||
|
ID string `json:"id" form:"id"` //设备编码
|
||||||
|
Status string `json:"status" form:"status"` //设备状态
|
||||||
|
Expire int `json:"expire" form:"expire"` //设备过期时间,及更新时间
|
||||||
|
}
|
||||||
|
|
@ -61,4 +61,21 @@ const (
|
||||||
NoUploadPermissions = 76 // 无上传权限
|
NoUploadPermissions = 76 // 无上传权限
|
||||||
DeleteFileFailed = 77 // 删除文件失败
|
DeleteFileFailed = 77 // 删除文件失败
|
||||||
DeleteFileInfoFailed = 78 // 删除文件信息失败
|
DeleteFileInfoFailed = 78 // 删除文件信息失败
|
||||||
|
|
||||||
|
DataFormatError = 80 // 数据格式错误
|
||||||
|
|
||||||
|
AddConfigFileFailed = 90 // 添加配置文件失败
|
||||||
|
UpdateConfigFailed = 91 // 更新配置失败
|
||||||
|
DeleteConfigFailed = 92 // 删除配置失败
|
||||||
|
SearchConfigFileFailed = 93 // 获取配置失败
|
||||||
|
|
||||||
|
ShellCreateFailed = 100 // 创建shell失败
|
||||||
|
ShellUpdateFailed = 101 // 更新shell失败
|
||||||
|
ShellDeleteFailed = 102 // 删除shell失败
|
||||||
|
ShellSearchFailed = 103 // 获取shell失败
|
||||||
|
|
||||||
|
//monitor部分错误码
|
||||||
|
MonitorServerIDIsNull = 110 // 监控服务器ID为空
|
||||||
|
MonitorServerIDNotFound = 111 // 监控服务器ID不存在
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
package proto
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type UpdateUserInfoReq struct {
|
type UpdateUserInfoReq struct {
|
||||||
ID int `json:"id" form:"id"` //用户id
|
ID int `json:"id" form:"id"` //用户id
|
||||||
Username string `json:"name" form:"name"` //用户名
|
Username string `json:"name" form:"name"` //用户名
|
||||||
|
|
@ -23,8 +27,119 @@ type CIDRUN struct {
|
||||||
|
|
||||||
// 用于执行函数,方法
|
// 用于执行函数,方法
|
||||||
type CronInfo struct {
|
type CronInfo struct {
|
||||||
Type int `json:"type" form:"type"` //类型编码,1日志清理(且只会有一个),其他待定
|
Type int `json:"type" form:"type"` //类型编码,1日志清理(且只会有一个),其他待定,2从服务器同步数据
|
||||||
Info string `json:"info" form:"info"` //信息
|
Info string `json:"info" form:"info"` //信息
|
||||||
Curr int `json:"curr" form:"curr"` //当前剩余时间,每次执行减10s小于等于0则执行
|
Curr int `json:"curr" form:"curr"` //当前剩余时间,每次执行减10s小于等于0则执行
|
||||||
Every int `json:"every" form:"every"` //每隔多少秒执行一次,小于等于0表示不执行,时间粒度为10s
|
Every int `json:"every" form:"every"` //每隔多少秒执行一次,小于等于0表示不执行,时间粒度为10s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 用户数据同步
|
||||||
|
type UserSync struct {
|
||||||
|
Update []UserAddOrUpdate `json:"update" form:"update"` //更新用户
|
||||||
|
Add []UserAddOrUpdate `json:"add" form:"add"` //添加用户
|
||||||
|
Delete []UserDelID `json:"delete" form:"delete"` //删除用户
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户数据同步确认
|
||||||
|
type UserSyncConfirm struct {
|
||||||
|
Add []UserConfirmID `json:"add" form:"add"` //添加用户
|
||||||
|
Update []UserConfirmID `json:"update" form:"update"` //更新用户
|
||||||
|
Delete []UserConfirmID `json:"delete" form:"delete"` //删除用户
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserConfirmID struct {
|
||||||
|
ID uint `json:"id" form:"id"` //用户id
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserDelID struct {
|
||||||
|
ID uint `json:"ID" form:"ID"` //用户id
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserAddOrUpdate struct {
|
||||||
|
ID uint `json:"ID" form:"ID"` //用户id
|
||||||
|
CreatedAt time.Time `json:"CreatedAt" form:"CreatedAt"` //创建时间
|
||||||
|
UpdatedAt time.Time `json:"UpdatedAt" form:"UpdatedAt"` //更新时间
|
||||||
|
DeletedAt time.Time `json:"DeletedAt" form:"DeletedAt"` //删除时间
|
||||||
|
Name string `json:"Name" form:"Name"` //用户名
|
||||||
|
Age int `json:"Age" form:"Age"` //年龄
|
||||||
|
Email string `json:"Email" form:"Email"` //邮箱
|
||||||
|
Password string `json:"Password" form:"Password"` //密码
|
||||||
|
Gender string `json:"Gender" form:"Gender"` //性别
|
||||||
|
Role string `json:"Role" form:"Role"` //角色
|
||||||
|
Redis bool `json:"Redis" form:"Redis"` //是否刷新redis
|
||||||
|
Run bool `json:"Run" form:"Run"` //是否运行
|
||||||
|
Upload bool `json:"Upload" form:"Upload"` //是否上传头像
|
||||||
|
VideoFunc bool `json:"VideoFunc" form:"VideoFunc"` //视频功能
|
||||||
|
DeviceFunc bool `json:"DeviceFunc" form:"DeviceFunc"`
|
||||||
|
CIDFunc bool `json:"CIDFunc" form:"CIDFunc"`
|
||||||
|
Avatar string `json:"Avatar" form:"Avatar"` //头像
|
||||||
|
CreateTime string `json:"CreateTime" form:"CreateTime"`
|
||||||
|
UpdateTime string `json:"UpdateTime" form:"UpdateTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据同步请求
|
||||||
|
type SyncUserReq struct {
|
||||||
|
Token string `json:"token" form:"token"`
|
||||||
|
Types int `json:"type" form:"type"` // 1为全量同步 2为增量同步
|
||||||
|
Device string `json:"device" form:"device"`
|
||||||
|
Confirm UserSyncConfirm `json:"confirm" form:"confirm"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// shell待执行
|
||||||
|
type SyncUserShellReq struct {
|
||||||
|
Token string `json:"token" form:"token"`
|
||||||
|
Server string `json:"server" form:"server"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateShellReq struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
ShellName string `json:"shell_name"`
|
||||||
|
ShellContent string `json:"shell_content"`
|
||||||
|
Server string `json:"server"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
ShellResult string `json:"shell_result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// shell 执行结果返回
|
||||||
|
type SyncUserShellResp struct {
|
||||||
|
Token string `json:"token" form:"token"`
|
||||||
|
Shells []UpdateShellReq `json:"shells" form:"shells"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateShellRespV2 struct {
|
||||||
|
ID uint `json:"id" form:"id"`
|
||||||
|
Status int `json:"status" form:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseOAuth struct {
|
||||||
|
ID uint `json:"id" form:"id"`
|
||||||
|
Name string `json:"name" form:"name"`
|
||||||
|
Email string `json:"email" form:"email"`
|
||||||
|
Token string `json:"token" form:"token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecretSyncSettings struct {
|
||||||
|
Prev string `json:"prev"` // 前一个secret
|
||||||
|
Curr string `json:"curr"` // 当前的secret
|
||||||
|
Next string `json:"next"` // 下一个secret
|
||||||
|
CurrExpectedExpiration int64 `json:"curr_expected_expiration"` // 当前密钥的预期过期时间戳
|
||||||
|
PrevEndTimestamp int64 `json:"prev_end_timestamp"` // 前一个secret的结束时间戳
|
||||||
|
CurrStartTimestamp int64 `json:"curr_start_timestamp"` // 当前secret的开始时间戳
|
||||||
|
NextStartTimestamp int64 `json:"next_start_timestamp"` // 下一个secret的开始时间戳
|
||||||
|
}
|
||||||
|
|
||||||
|
type SyncSystemConfigRequest struct {
|
||||||
|
//时间戳
|
||||||
|
Timestamp int64 `json:"timestamp" form:"timestamp"` // 时间戳
|
||||||
|
//设备标识
|
||||||
|
DeviceApp string `json:"device_app" form:"device_app"` // 设备标识
|
||||||
|
//加密信息
|
||||||
|
Sign string `json:"sign" form:"sign"` // 加密信息,app的secret加密后的值
|
||||||
|
SecretKeyMd5 string `json:"secret_key_md5" form:"secret_key_md5"` // 密钥的MD5值,用于验证
|
||||||
|
}
|
||||||
|
|
||||||
|
type RequestSyncSecretResp struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data string `json:"data"`
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,17 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
"videoplayer/dao"
|
||||||
"videoplayer/proto"
|
"videoplayer/proto"
|
||||||
"videoplayer/worker"
|
"videoplayer/worker"
|
||||||
)
|
)
|
||||||
|
|
@ -34,7 +39,6 @@ func SaveFile(c *gin.Context, file *multipart.FileHeader, uploadType string) (st
|
||||||
//生成文件路径
|
//生成文件路径
|
||||||
path_ := getFilePath(proto.FILE_BASE_DIR)
|
path_ := getFilePath(proto.FILE_BASE_DIR)
|
||||||
filePath := path_ + "/" + fileStoreName
|
filePath := path_ + "/" + fileStoreName
|
||||||
|
|
||||||
//保存文件
|
//保存文件
|
||||||
if err := c.SaveUploadedFile(file, filePath); err != nil {
|
if err := c.SaveUploadedFile(file, filePath); err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
|
|
@ -45,3 +49,171 @@ func SaveFile(c *gin.Context, file *multipart.FileHeader, uploadType string) (st
|
||||||
|
|
||||||
return path_, fileStoreName, nil
|
return path_, fileStoreName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CalculateFileMd5(file io.Reader) string {
|
||||||
|
hash := md5.New()
|
||||||
|
if _, err := io.Copy(hash, file); err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%x", hash.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckUploadRequestParameters(req *proto.FileUploadReq) error {
|
||||||
|
var err error
|
||||||
|
if req.AuthType == "" {
|
||||||
|
err = fmt.Errorf("auth_type is empty")
|
||||||
|
}
|
||||||
|
if req.UploadType == "" {
|
||||||
|
req.UploadType = "1"
|
||||||
|
}
|
||||||
|
if req.UploadType != "1" {
|
||||||
|
req.UploadType = "2"
|
||||||
|
}
|
||||||
|
if proto.File_Type[req.Type] == 0 {
|
||||||
|
err = fmt.Errorf("file type is invalid")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateConfigFile(req *proto.AddConfigFileReq, userId int) error {
|
||||||
|
var err error
|
||||||
|
user := GetUserByIDWithCache(userId)
|
||||||
|
if user.ID == 0 || user.Role != "admin" {
|
||||||
|
err = fmt.Errorf("user not found or no permission")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if req.FileName == "" || req.FilePath == "" {
|
||||||
|
err = fmt.Errorf("file name or file path is empty")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//查看系统中是否存在文件,不存在则创建
|
||||||
|
file := req.FilePath + "/" + req.FileName
|
||||||
|
//正则判断文件名是否合法
|
||||||
|
pattern := `^/([^/:\*?]+/)*([^/:\*?]+)?$`
|
||||||
|
reg := regexp.MustCompile(pattern)
|
||||||
|
if reg.MatchString(file) == false {
|
||||||
|
err = fmt.Errorf("file path is invalid")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, fileErr := os.Stat(file)
|
||||||
|
if fileErr != nil {
|
||||||
|
//创建文件
|
||||||
|
f, err2 := os.Create(file)
|
||||||
|
if err2 != nil {
|
||||||
|
err = err2
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func(f *os.File) {
|
||||||
|
err := f.Close()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error closing file")
|
||||||
|
}
|
||||||
|
}(f)
|
||||||
|
}
|
||||||
|
//创建
|
||||||
|
configFile := dao.ConfigFile{FilePath: req.FilePath, FileName: req.FileName, AuthID: userId}
|
||||||
|
_, err3 := dao.CreateConfigFile(configFile)
|
||||||
|
if err3 != nil {
|
||||||
|
err = err3
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteConfigFile(req *proto.ConfigFileReq, userId int) error {
|
||||||
|
var err error
|
||||||
|
user := GetUserByIDWithCache(userId)
|
||||||
|
if user.ID == 0 || user.Role != "admin" {
|
||||||
|
err = fmt.Errorf("user not found or no permission")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//删除文件
|
||||||
|
config_file := dao.FindConfigFileByID(req.ID, userId)
|
||||||
|
if config_file.ID == 0 {
|
||||||
|
err = fmt.Errorf("config file not found")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = dao.DeleteConfigFileByID(req.ID)
|
||||||
|
if req.DelFile {
|
||||||
|
file := config_file.FilePath + "/" + config_file.FileName
|
||||||
|
err = os.Remove(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//删除数据库记录
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigFileService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConfigFileService) UpdateConfigFile(req *proto.ConfigFileReq, userId int) error {
|
||||||
|
var err error
|
||||||
|
user := GetUserByIDWithCache(userId)
|
||||||
|
if user.ID == 0 || user.Role != "admin" {
|
||||||
|
err = fmt.Errorf("user not found or no permission")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
config_file := dao.FindConfigFileByID(req.ID, userId)
|
||||||
|
if config_file.ID == 0 {
|
||||||
|
err = fmt.Errorf("config file not found")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//修改文件名
|
||||||
|
if req.FileName != "" {
|
||||||
|
file := config_file.FilePath + "/" + config_file.FileName
|
||||||
|
new_file := config_file.FilePath + "/" + req.FileName
|
||||||
|
err = os.Rename(file, new_file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = dao.UpdateConfigFileByID(req.ID, dao.ConfigFile{FileName: req.FileName})
|
||||||
|
}
|
||||||
|
if req.Content != "" {
|
||||||
|
file := config_file.FilePath + "/" + config_file.FileName
|
||||||
|
f, err2 := os.OpenFile(file, os.O_WRONLY|os.O_TRUNC, 0644) //打开文件,清空文件内容,写入新内容,不存在则创建
|
||||||
|
if err2 != nil {
|
||||||
|
err = err2
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func(f *os.File) {
|
||||||
|
err3 := f.Close()
|
||||||
|
if err3 != nil {
|
||||||
|
fmt.Println("Error closing file")
|
||||||
|
}
|
||||||
|
}(f)
|
||||||
|
_, err = f.WriteString(req.Content)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConfigFileService) SearchOneConfigFile(req *proto.ConfigFileReq, userId int) ([]proto.SearchOneConfigFileResp, error) {
|
||||||
|
user := GetUserByIDWithCache(userId)
|
||||||
|
if user.ID == 0 || user.Role != "admin" {
|
||||||
|
return []proto.SearchOneConfigFileResp{}, fmt.Errorf("user not found or no permission")
|
||||||
|
}
|
||||||
|
config_file := dao.FindConfigFileByID(req.ID, userId)
|
||||||
|
if config_file.ID == 0 {
|
||||||
|
return []proto.SearchOneConfigFileResp{}, fmt.Errorf("config file not found")
|
||||||
|
}
|
||||||
|
file := config_file.FilePath + "/" + config_file.FileName
|
||||||
|
content, err2 := os.ReadFile(file)
|
||||||
|
if err2 != nil {
|
||||||
|
return []proto.SearchOneConfigFileResp{}, err2
|
||||||
|
}
|
||||||
|
resp := []proto.SearchOneConfigFileResp{{ID: config_file.ID, FilePath: config_file.FilePath, FileName: config_file.FileName, Content: string(content), CreatedAt: config_file.CreatedAt, UpdatedAt: config_file.UpdatedAt}}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConfigFileService) SearchAllConfigFile(userId int) ([]dao.ConfigFile, error) {
|
||||||
|
user := GetUserByIDWithCache(userId)
|
||||||
|
if user.ID == 0 || user.Role != "admin" {
|
||||||
|
return []dao.ConfigFile{}, fmt.Errorf("user not found or no permission")
|
||||||
|
}
|
||||||
|
config_files := dao.FindConfigFileByAuthID(userId)
|
||||||
|
return config_files, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"videoplayer/dao"
|
||||||
|
"videoplayer/proto"
|
||||||
|
"videoplayer/worker"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateShell(shellName, shellContent, server string, uid int) uint {
|
||||||
|
id := dao.CreateShell(shellName, shellContent, server, uint(uid))
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindShellByAuthID(id int) []dao.Shell {
|
||||||
|
return dao.FindShellByAuthID(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteShellByID(id, authId uint) bool {
|
||||||
|
user := GetUserByIDFromUserCenter(int(authId))
|
||||||
|
if user.Role == "admin" {
|
||||||
|
return dao.DeleteShellByIDV2(id)
|
||||||
|
}
|
||||||
|
return dao.DeleteShellByID(id, authId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateShellByID(id, authId uint, shellName, shellContent, server string, status int, shellResult string) bool {
|
||||||
|
return dao.UpdateShellByID(id, authId, shellName, shellContent, status, shellResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindShellWillRunByServer(server string, uid int) ([]dao.Shell, error) {
|
||||||
|
var shells []dao.Shell
|
||||||
|
var err error
|
||||||
|
if server == "" {
|
||||||
|
//err设置为server为空
|
||||||
|
err = errors.New("server is empty")
|
||||||
|
return shells, err
|
||||||
|
}
|
||||||
|
shells = dao.FindShellWillRunByServer(server, uint(uid))
|
||||||
|
//设置状态为执行中
|
||||||
|
for _, v := range shells {
|
||||||
|
dao.UpdateShellByID(v.ID, uint(uid), v.ShellName, v.ShellContent, v.Status+1, v.ShellResult)
|
||||||
|
}
|
||||||
|
return shells, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从服务器定时获取shell、执行并返回结果
|
||||||
|
func ShellWillRunFromServer() {
|
||||||
|
shells, err := GetShellWillRunFromMaster(proto.Config.SERVER_NAME)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var resp []proto.UpdateShellReq
|
||||||
|
|
||||||
|
for _, v := range shells {
|
||||||
|
//执行shell脚本,go执行命令
|
||||||
|
res, err2 := RunShell(v.ShellContent)
|
||||||
|
if err2 != "" {
|
||||||
|
resp = append(resp, proto.UpdateShellReq{ID: v.ID, Server: v.Server, Status: 2, ShellResult: err2})
|
||||||
|
} else {
|
||||||
|
resp = append(resp, proto.UpdateShellReq{ID: v.ID, Server: v.Server, Status: 2, ShellResult: res})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(resp) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//返回执行结果
|
||||||
|
url := "https://" + proto.Config.MASTER_SERVER_DOMAIN + "/shell/update?super_id=1"
|
||||||
|
var req proto.SyncUserShellResp
|
||||||
|
req.Token = worker.GetRedisSetMembers("super_permission_tokens")[0]
|
||||||
|
req.Shells = resp
|
||||||
|
resp_data, err := worker.SyncDataFromMasterShellReq3(url, req)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//更新执行结果
|
||||||
|
for _, v := range resp_data {
|
||||||
|
if v.Status < 0 {
|
||||||
|
log.Fatalln("update shell failed:", v.ID, v.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从服务器从主服务器获取待执行的shell
|
||||||
|
func GetShellWillRunFromMaster(server string) ([]dao.Shell, error) {
|
||||||
|
master := proto.Config.MASTER_SERVER_DOMAIN
|
||||||
|
//发起请求获取待执行的shell
|
||||||
|
url := "https://" + master + "/shell/server_will_run_list?super_id=1"
|
||||||
|
var req proto.SyncUserShellReq
|
||||||
|
req.Server = server
|
||||||
|
superPermissions := worker.GetRedisSetMembers("super_permission_tokens")
|
||||||
|
if len(superPermissions) == 0 {
|
||||||
|
log.Println("get shell will run from master error: no super permission tokens found, please check the configuration or redis!")
|
||||||
|
return nil, errors.New("no super permission tokens found")
|
||||||
|
}
|
||||||
|
req.Token = superPermissions[0]
|
||||||
|
shells, err := worker.SyncDataFromMasterShellReq2(url, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return shells, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunShell(script string) (res, err string) {
|
||||||
|
cmd := exec.Command("/bin/bash", "-c", script)
|
||||||
|
// 使用bytes.Buffer捕获输出
|
||||||
|
var out bytes.Buffer
|
||||||
|
cmd.Stdout = &out
|
||||||
|
err3 := cmd.Run()
|
||||||
|
err3_info := ""
|
||||||
|
if err3 != nil {
|
||||||
|
err3_info = err3.Error()
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(out.String()), err3_info
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
"videoplayer/proto"
|
"videoplayer/proto"
|
||||||
"videoplayer/worker"
|
"videoplayer/worker"
|
||||||
|
|
@ -68,3 +74,246 @@ func GetToolRedis(key string) (code int, message string) {
|
||||||
return proto.SuccessCode, val
|
return proto.SuccessCode, val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetAllRedis() (code int, msg string, data []worker.RedisInfo) {
|
||||||
|
data, err := worker.GetAllRedisInfo()
|
||||||
|
if err != nil {
|
||||||
|
return proto.OperationFailed, err.Error(), nil
|
||||||
|
}
|
||||||
|
return proto.SuccessCode, "success", data
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendEmail(email, subject, body string) {
|
||||||
|
//捕获异常
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
fmt.Errorf("tool send mail error: %s", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// TODO
|
||||||
|
// 发送邮件
|
||||||
|
// 邮件内容
|
||||||
|
// 邮件标题
|
||||||
|
// 收件人
|
||||||
|
// 发送邮件
|
||||||
|
// 发送邮件通知
|
||||||
|
// 发送邮件通知
|
||||||
|
var em worker.MyEmail
|
||||||
|
em.SmtpPassword = "nihzazdkmucnbhid"
|
||||||
|
em.SmtpHost = "pop.qq.com:587"
|
||||||
|
em.SmtpUserName = "354425203@qq.com"
|
||||||
|
em.SmtpPort = 587
|
||||||
|
em.ImapPort = 993
|
||||||
|
err := em.Send(subject, body, []string{email})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("send mail error:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 地址校验
|
||||||
|
func CheckEmail(email string) bool {
|
||||||
|
//正则表达式判断是否是邮箱
|
||||||
|
pattern := `^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+$`
|
||||||
|
reg := regexp.MustCompile(pattern)
|
||||||
|
return reg.MatchString(email)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取监控设备及状态
|
||||||
|
func GetMonitorDeviceListWithStatus(userId int) ([]proto.GetMonitorDeviceStatus, error) {
|
||||||
|
var deviceStatus []proto.GetMonitorDeviceStatus
|
||||||
|
user := GetUserByIDFromUserCenter(userId)
|
||||||
|
if user.Role != "admin" {
|
||||||
|
return deviceStatus, errors.New("user is not admin, can not get monitor device list")
|
||||||
|
} else {
|
||||||
|
devices := worker.GetRedisSetMembers(proto.Config.MONITOR_SERVER_TOKEN)
|
||||||
|
for _, device := range devices {
|
||||||
|
status, expireIn := worker.GetRedisWithExpire("monitor_" + device)
|
||||||
|
var deviceInfo proto.GetMonitorDeviceStatus
|
||||||
|
deviceInfo.ID = device
|
||||||
|
deviceInfo.Expire = expireIn
|
||||||
|
if status == "" {
|
||||||
|
deviceInfo.Status = "offline"
|
||||||
|
} else {
|
||||||
|
deviceInfo.Status = status
|
||||||
|
}
|
||||||
|
deviceStatus = append(deviceStatus, deviceInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceStatus, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateMonitorDeviceListWithStatus(userId int, deviceReq []proto.GetMonitorDeviceStatus) error {
|
||||||
|
user := GetUserByIDFromUserCenter(userId)
|
||||||
|
var err error
|
||||||
|
if user.Role != "admin" {
|
||||||
|
err = errors.New("user is not admin, can not update monitor device list")
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
// 更新监控设备状态.如果在集合中则添加,不在则添加到集合中
|
||||||
|
devices := worker.GetRedisSetMembers(proto.Config.MONITOR_SERVER_TOKEN)
|
||||||
|
deviceMap := make(map[string]bool, len(devices))
|
||||||
|
for _, device := range devices {
|
||||||
|
deviceMap[device] = true
|
||||||
|
}
|
||||||
|
for _, device := range deviceReq {
|
||||||
|
if _, ok := deviceMap[device.ID]; ok {
|
||||||
|
// 如果设备在集合中,则更新状态
|
||||||
|
worker.SetRedisWithExpire("monitor_"+device.ID, device.Status, time.Duration(device.Expire)*time.Second)
|
||||||
|
} else {
|
||||||
|
worker.SetRedisSetAdd(proto.Config.MONITOR_SERVER_TOKEN, device.ID)
|
||||||
|
worker.SetRedisWithExpire("monitor_"+device.ID, device.Status, time.Duration(device.Expire)*time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func DelMonitorDeviceListWithStatus(userId int, deviceReq []proto.GetMonitorDeviceStatus) ([]proto.GetMonitorDeviceStatus, error) {
|
||||||
|
user := GetUserByIDFromUserCenter(userId)
|
||||||
|
var err error
|
||||||
|
var delDevices []proto.GetMonitorDeviceStatus
|
||||||
|
if user.Role != "admin" {
|
||||||
|
err = errors.New("user is not admin, can not update monitor device list")
|
||||||
|
return delDevices, err
|
||||||
|
} else {
|
||||||
|
for _, device := range deviceReq {
|
||||||
|
if worker.IsContainSet(proto.Config.MONITOR_SERVER_TOKEN, device.ID) {
|
||||||
|
// 如果设备在集合中,则删除状态
|
||||||
|
worker.DelRedis("monitor_" + device.ID)
|
||||||
|
worker.SetRedisSetRemove(proto.Config.MONITOR_SERVER_TOKEN, device.ID)
|
||||||
|
delDevices = append(delDevices, device)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return delDevices, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新token密钥
|
||||||
|
func SyncTokenSecretFromUserCenter() {
|
||||||
|
secretSettings, err := GetTokenSecretFromUserCenter()
|
||||||
|
//写入redis
|
||||||
|
secretSettingsBytes, err2 := json.Marshal(secretSettings)
|
||||||
|
if err2 != nil {
|
||||||
|
log.Println("SyncTokenSecretFromUserCenter json marshal error:", err2)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if proto.SyncSecretReqLog%100 == 0 {
|
||||||
|
log.Println("SyncTokenSecretFromUserCenter req data:", string(secretSettingsBytes))
|
||||||
|
}
|
||||||
|
worker.SetRedis("secret_sync_settings", string(secretSettingsBytes)) //将密钥信息存入redis
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println("SyncTokenSecretFromUserCenter error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if secretSettings.Curr != "" && secretSettings.Curr != proto.TOKEN_SECRET && secretSettings.Next == "" { //如果当前密钥不为空且不等于配置文件中的密钥,并且下一个密钥为空,则需要更新配置文件中的密钥
|
||||||
|
log.Printf("SyncTokenSecretFromUserCenter current secret is not equal to config secret, current: %s, config: %s\n", secretSettings.Curr, proto.TOKEN_SECRET)
|
||||||
|
//如果当前密钥与配置文件中的密钥不一致,则需要更新配置文件中的密钥
|
||||||
|
proto.SigningKeyRWLock.Lock()
|
||||||
|
proto.SigningKey = []byte(secretSettings.Curr)
|
||||||
|
proto.Config.TOKEN_SECRET = secretSettings.Curr
|
||||||
|
proto.SigningKeyRWLock.Unlock()
|
||||||
|
//配置写回文件
|
||||||
|
go proto.WriteConfigToFile()
|
||||||
|
log.Println("SyncTokenSecretFromUserCenter current secret updated successfully")
|
||||||
|
}
|
||||||
|
|
||||||
|
if secretSettings.Next == "" {
|
||||||
|
log.Println("SyncTokenSecretFromUserCenter secret is empty")
|
||||||
|
return
|
||||||
|
} else if proto.SyncSecretReqLog%100 == 0 {
|
||||||
|
go SetNextSecretToCurrent(*secretSettings) //异步设置下一个密钥为当前密钥
|
||||||
|
}
|
||||||
|
|
||||||
|
proto.SyncSecretReqLog++ //记录同步密钥请求次数
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetNextSecretToCurrent(secret_copy proto.SecretSyncSettings) {
|
||||||
|
var secret_sync_settings proto.SecretSyncSettings
|
||||||
|
redisKey := "secret_sync_settings"
|
||||||
|
settingsStr := worker.GetRedis(redisKey)
|
||||||
|
err := json.Unmarshal([]byte(settingsStr), &secret_sync_settings)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error decoding secret sync settings:", err)
|
||||||
|
} else {
|
||||||
|
//如果当前密钥的下一个密钥与传入的密钥不一致,则不进行设置
|
||||||
|
if secret_copy.Next != secret_sync_settings.Next {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//获取需要等待时间
|
||||||
|
waitTime := secret_sync_settings.NextStartTimestamp - worker.GetCurrentTimestamp()
|
||||||
|
if waitTime > 0 {
|
||||||
|
log.Printf("Waiting for %d seconds before setting the next secret as current secret\n", waitTime)
|
||||||
|
time.Sleep(time.Duration(waitTime) * time.Second) //等待时间
|
||||||
|
} else {
|
||||||
|
log.Println("No need to wait, setting the next secret as current secret immediately")
|
||||||
|
}
|
||||||
|
//设置下一个密钥为当前密钥
|
||||||
|
secret_sync_settings.Prev = secret_sync_settings.Curr
|
||||||
|
secret_sync_settings.PrevEndTimestamp = worker.GetCurrentTimestamp()
|
||||||
|
secret_sync_settings.Curr = secret_sync_settings.Next
|
||||||
|
secret_sync_settings.Next = ""
|
||||||
|
secret_sync_settings.CurrStartTimestamp = secret_sync_settings.PrevEndTimestamp
|
||||||
|
|
||||||
|
//设置当前程序的密钥
|
||||||
|
//获取写锁
|
||||||
|
proto.SigningKeyRWLock.Lock()
|
||||||
|
defer proto.SigningKeyRWLock.Unlock()
|
||||||
|
proto.SigningKey = []byte(secret_sync_settings.Curr)
|
||||||
|
|
||||||
|
proto.Config.TOKEN_SECRET = secret_sync_settings.Curr
|
||||||
|
//配置写回文件
|
||||||
|
go proto.WriteConfigToFile()
|
||||||
|
}
|
||||||
|
settinsStr, err2 := json.Marshal(secret_sync_settings)
|
||||||
|
if err2 != nil {
|
||||||
|
log.Println("Error encoding set secret sync settings:", err2)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
worker.SetRedis(redisKey, string(settinsStr)) //将当前的密钥信息存入redis
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取token密钥请求
|
||||||
|
func GetTokenSecretFromUserCenter() (*proto.SecretSyncSettings, error) {
|
||||||
|
url := "https://uc.ljsea.top/tool/sync_system_config"
|
||||||
|
var req proto.SyncSystemConfigRequest
|
||||||
|
proto.SigningKeyRWLock.Lock()
|
||||||
|
defer proto.SigningKeyRWLock.Unlock()
|
||||||
|
req.SecretKeyMd5 = worker.GenerateMD5(string(proto.SigningKey))
|
||||||
|
req.DeviceApp = "StuAcaWorksAI"
|
||||||
|
req.Timestamp = worker.GetCurrentTimestamp()
|
||||||
|
req.Sign = worker.GenerateMD5(req.SecretKeyMd5 + req.DeviceApp + strconv.FormatInt(req.Timestamp, 10))
|
||||||
|
reqBytes, err2 := json.Marshal(req)
|
||||||
|
if err2 != nil {
|
||||||
|
log.Println("GetTokenSecretFromUserCenter json marshal error:", err2)
|
||||||
|
return nil, err2
|
||||||
|
}
|
||||||
|
err, resp := worker.DoPostRequestJSON(url, reqBytes, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("GetTokenSecretFromUserCenter post request error:", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var respObject proto.RequestSyncSecretResp
|
||||||
|
err = json.Unmarshal(resp, &respObject)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("GetTokenSecretFromUserCenter json unmarshal error:", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//对称加密密钥。通过密钥加 secret_key 取md5
|
||||||
|
secretKeyMd5 := worker.GenerateMD5(proto.TOKEN_SECRET + "_sync_secret")
|
||||||
|
|
||||||
|
//解密返回数据
|
||||||
|
dataContent, err2 := worker.AESDecrypt(respObject.Data, []byte(secretKeyMd5))
|
||||||
|
if err2 != nil {
|
||||||
|
log.Println("GetTokenSecretFromUserCenter aes decrypt error:", err2)
|
||||||
|
return nil, err2
|
||||||
|
}
|
||||||
|
var secretResp proto.SecretSyncSettings
|
||||||
|
err = json.Unmarshal(dataContent, &secretResp)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("GetTokenSecretFromUserCenter json unmarshal error:", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &secretResp, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,29 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/golang-jwt/jwt"
|
||||||
|
"log"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
"videoplayer/dao"
|
"videoplayer/dao"
|
||||||
"videoplayer/proto"
|
"videoplayer/proto"
|
||||||
|
"videoplayer/worker"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateUser(name, password, email, gender string, age int) uint {
|
func CreateUser(name, password, email, gender string, age int) uint {
|
||||||
return dao.CreateUser(name, password, email, gender, age)
|
id := dao.CreateUser(name, password, email, gender, age)
|
||||||
|
if id != 0 {
|
||||||
|
//添加用户信息到同步列表
|
||||||
|
err := setSyncUserDataSet("add", int(id))
|
||||||
|
if err != nil {
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUser(name, email, password string) dao.User {
|
func GetUser(name, email, password string) dao.User {
|
||||||
|
|
@ -38,6 +54,38 @@ func GetUserByID(id int) []proto.User {
|
||||||
return dao.FindUserByID(id)
|
return dao.FindUserByID(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取用户信息,有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
|
||||||
|
}
|
||||||
|
|
||||||
func GetUserByNameLike(name string) []proto.User {
|
func GetUserByNameLike(name string) []proto.User {
|
||||||
return dao.FindUserByNameLike(name)
|
return dao.FindUserByNameLike(name)
|
||||||
}
|
}
|
||||||
|
|
@ -46,12 +94,384 @@ func UpdateUser(user_id int, req proto.UpdateUserInfoReq) (int, error) {
|
||||||
cur_user := dao.FindUserByID2(user_id)
|
cur_user := dao.FindUserByID2(user_id)
|
||||||
//fmt.Println("cur_user:", cur_user, "req:", req)
|
//fmt.Println("cur_user:", cur_user, "req:", req)
|
||||||
if user_id == req.ID && cur_user.Role != "admin" {
|
if user_id == req.ID && cur_user.Role != "admin" {
|
||||||
dao.UpdateUserByID3(user_id, req) //用户修改自己的信息,不能修改权限信息
|
err := dao.UpdateUserByID3(user_id, req) //用户修改自己的信息,不能修改权限信息
|
||||||
return user_id, nil
|
//添加修改用户信息到同步列表
|
||||||
|
if err == nil {
|
||||||
|
err2 := setSyncUserDataSet("update", user_id)
|
||||||
|
UpdateUserCache(user_id)
|
||||||
|
if err2 != nil {
|
||||||
|
fmt.Println("set sync user data set error:", err2)
|
||||||
|
return user_id, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return user_id, err
|
||||||
} else if cur_user.Role == "admin" {
|
} else if cur_user.Role == "admin" {
|
||||||
dao.UpdateUserByID2(req.ID, req)
|
err := dao.UpdateUserByID2(req.ID, req)
|
||||||
|
if err == nil {
|
||||||
|
//添加修改用户信息到同步列表
|
||||||
|
err2 := setSyncUserDataSet("update", req.ID)
|
||||||
|
UpdateUserCache(req.ID)
|
||||||
|
if err2 != nil {
|
||||||
|
fmt.Println("set sync user data set error:", err2)
|
||||||
|
return req.ID, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
return req.ID, nil
|
return req.ID, nil
|
||||||
} else {
|
} else {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UpdateUserCache(id int) {
|
||||||
|
key := "user_info_" + strconv.Itoa(id)
|
||||||
|
if worker.IsContainKey(key) {
|
||||||
|
users := GetUserByID(id)
|
||||||
|
userJson, err := json.Marshal(users[0]) //统一使用User不使用数组
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("get user info , json marshal error:", err)
|
||||||
|
}
|
||||||
|
success := worker.SetRedis(key, string(userJson))
|
||||||
|
if !success {
|
||||||
|
fmt.Println("set redis error,user json:", string(userJson))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteUserService(id, user_id int) int {
|
||||||
|
res := 0
|
||||||
|
if user_id == id {
|
||||||
|
res = dao.DeleteUserByID(id)
|
||||||
|
} else {
|
||||||
|
user := dao.FindUserByID2(user_id)
|
||||||
|
if user.Role == "admin" {
|
||||||
|
res = dao.DeleteUserByID(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if res != 0 {
|
||||||
|
//添加删除用户信息到同步列表
|
||||||
|
err := setSyncUserDataSet("delete", id)
|
||||||
|
if err != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
func UserSyncDataFromMaster() {
|
||||||
|
//从接口获取数据
|
||||||
|
url := "https://" + proto.Config.MASTER_SERVER_DOMAIN + "/user/sync"
|
||||||
|
tokens := worker.GetRedisSetMembers("super_permission_tokens")
|
||||||
|
var req proto.SyncUserReq
|
||||||
|
req.Token = tokens[0]
|
||||||
|
req.Device = proto.Config.SERVER_NAME
|
||||||
|
all := worker.GetRedis("user_sync_all")
|
||||||
|
is_all := false //是否全量同步
|
||||||
|
if all == "" || all == "1" {
|
||||||
|
is_all = true
|
||||||
|
//清空数据表
|
||||||
|
err := dao.ClearAllUsers()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("All ClearAllUsers error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
worker.SetRedisForever("user_sync_all", "1")
|
||||||
|
req.Types = 1
|
||||||
|
} else {
|
||||||
|
worker.SetRedisForever("user_sync_all", "2")
|
||||||
|
req.Types = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
user_sync_data, err := worker.SyncDataFromMasterReq2(url, req)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("UserSyncDataFromMaster error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
add_users := user_sync_data.Add
|
||||||
|
update_users := user_sync_data.Update
|
||||||
|
delete_users := user_sync_data.Delete
|
||||||
|
//未成功操作的id
|
||||||
|
var fail_ids []uint
|
||||||
|
|
||||||
|
//添加用户
|
||||||
|
var add_confirm []proto.UserConfirmID
|
||||||
|
for _, v := range add_users {
|
||||||
|
res := dao.AddUserSync(v)
|
||||||
|
if res == 0 {
|
||||||
|
fail_ids = append(fail_ids, v.ID)
|
||||||
|
} else {
|
||||||
|
add_confirm = append(add_confirm, proto.UserConfirmID{ID: v.ID})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//更新用户
|
||||||
|
var update_confirm []proto.UserConfirmID
|
||||||
|
for _, v := range update_users {
|
||||||
|
res := dao.UpdateUserSync(v)
|
||||||
|
if res == 0 {
|
||||||
|
fail_ids = append(fail_ids, v.ID)
|
||||||
|
} else {
|
||||||
|
update_confirm = append(update_confirm, proto.UserConfirmID{ID: v.ID})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//删除用户
|
||||||
|
var delete_confirm []proto.UserConfirmID
|
||||||
|
for _, v := range delete_users {
|
||||||
|
res := dao.DeleteUserSync(v)
|
||||||
|
if res == 0 {
|
||||||
|
fail_ids = append(fail_ids, v.ID)
|
||||||
|
} else {
|
||||||
|
delete_confirm = append(delete_confirm, proto.UserConfirmID{ID: v.ID})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//确认同步数据
|
||||||
|
if is_all == false {
|
||||||
|
var data proto.UserSyncConfirm
|
||||||
|
data.Add = add_confirm
|
||||||
|
data.Update = update_confirm
|
||||||
|
data.Delete = delete_confirm
|
||||||
|
//确认同步数据请求
|
||||||
|
var confirm_req proto.SyncUserReq
|
||||||
|
confirm_req.Token = tokens[0]
|
||||||
|
confirm_req.Device = proto.Config.SERVER_NAME
|
||||||
|
confirm_req.Types = 3
|
||||||
|
confirm_req.Confirm = data
|
||||||
|
worker.SyncDataFromMasterReq2(url, confirm_req)
|
||||||
|
} else {
|
||||||
|
worker.SetRedisForever("user_sync_all", "2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步数据到主服务器-增删改数据
|
||||||
|
func GetUserSyncData(device string) dao.UserSyncResp {
|
||||||
|
key := device + "_sync_user_ids"
|
||||||
|
add_temp_key := device + "_sync_user_ids_add_confirm_temp"
|
||||||
|
update_temp_key := device + "_sync_user_ids_update_confirm_temp"
|
||||||
|
delete_temp_key := device + "_sync_user_ids_delete_confirm_temp"
|
||||||
|
//需要获取暂存集合的并集,清空暂存集合,存入待确认集合
|
||||||
|
add_user_ids := worker.GetRedisSetUnion(key+"_add", add_temp_key)
|
||||||
|
update_user_ids := worker.GetRedisSetUnion(key+"_update", update_temp_key)
|
||||||
|
delete_user_ids := worker.GetRedisSetUnion(key+"_delete", delete_temp_key)
|
||||||
|
add_users := []dao.User{}
|
||||||
|
update_users := []dao.User{}
|
||||||
|
delete_users := []proto.UserDelID{}
|
||||||
|
for _, v := range add_user_ids {
|
||||||
|
id, _ := strconv.Atoi(v)
|
||||||
|
user := dao.FindUserByUserID(id)
|
||||||
|
add_users = append(add_users, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range update_user_ids {
|
||||||
|
id, _ := strconv.Atoi(v)
|
||||||
|
user := dao.FindUserByUserID(id)
|
||||||
|
update_users = append(update_users, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range delete_user_ids {
|
||||||
|
id, _ := strconv.Atoi(v)
|
||||||
|
delete_users = append(delete_users, proto.UserDelID{ID: uint(id)})
|
||||||
|
}
|
||||||
|
//将id存入暂存集合,清空原集合,存入待确认集合主要保证在确认时,有新的数据加入不会在确认时漏掉
|
||||||
|
worker.SetRedisSetUnionAndStore(add_temp_key, key+"_add")
|
||||||
|
worker.ClearRedisSet(key + "_add")
|
||||||
|
worker.SetRedisSetUnionAndStore(update_temp_key, key+"_update")
|
||||||
|
worker.ClearRedisSet(key + "_update")
|
||||||
|
worker.SetRedisSetUnionAndStore(delete_temp_key, key+"_delete")
|
||||||
|
worker.ClearRedisSet(key + "_delete")
|
||||||
|
return dao.UserSyncResp{Add: add_users, Update: update_users, Delete: delete_users}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setSyncUserDataSet(t string, id int) error {
|
||||||
|
devices := worker.GetRedisSetMembers("sync_devices_ids") //主服务器查看从服务器的设备列表
|
||||||
|
fmt.Println("set sync user data set devices:", devices, "t:", t, "id:", id)
|
||||||
|
var err error
|
||||||
|
for _, device := range devices {
|
||||||
|
key := device + "_sync_user_ids"
|
||||||
|
if t == "add" {
|
||||||
|
key_ := key + "_add"
|
||||||
|
worker.SetRedisSetAdd(key_, strconv.Itoa(id))
|
||||||
|
} else if t == "update" {
|
||||||
|
key_ := key + "_update"
|
||||||
|
worker.SetRedisSetAdd(key_, strconv.Itoa(id))
|
||||||
|
} else if t == "delete" {
|
||||||
|
key_ := key + "_delete"
|
||||||
|
worker.SetRedisSetAdd(key_, strconv.Itoa(id))
|
||||||
|
} else {
|
||||||
|
err = errors.New("error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认同步数据
|
||||||
|
func ConfirmSyncUserData(device string, data proto.UserSyncConfirm) error {
|
||||||
|
var err error
|
||||||
|
if len(data.Add) > 0 {
|
||||||
|
var ids_add []string
|
||||||
|
|
||||||
|
for _, v := range data.Add {
|
||||||
|
ids_add = append(ids_add, strconv.Itoa(int(v.ID)))
|
||||||
|
}
|
||||||
|
add_key := device + "_sync_user_ids_add_confirm"
|
||||||
|
isSuccess := worker.SetRedisSetAddBatchWithExpire(add_key, ids_add, time.Second*30)
|
||||||
|
if !isSuccess {
|
||||||
|
err = errors.New("set add confirm error")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ids_add_confirm_temp := device + "_sync_user_ids_add_confirm_temp"
|
||||||
|
//取差集
|
||||||
|
add_diff := worker.SetRedisSetDiffAndStore(ids_add_confirm_temp, add_key)
|
||||||
|
if add_diff == false {
|
||||||
|
err = errors.New("add diff error")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data.Update) > 0 {
|
||||||
|
|
||||||
|
var ids_update []string
|
||||||
|
for _, v := range data.Update {
|
||||||
|
ids_update = append(ids_update, strconv.Itoa(int(v.ID)))
|
||||||
|
}
|
||||||
|
update_key := device + "_sync_user_ids_update_confirm"
|
||||||
|
isSuccess := worker.SetRedisSetAddBatchWithExpire(update_key, ids_update, time.Second*30)
|
||||||
|
if !isSuccess {
|
||||||
|
err = errors.New("set update confirm error")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ids_update_confirm_temp := device + "_sync_user_ids_update_confirm_temp"
|
||||||
|
|
||||||
|
update_diff := worker.SetRedisSetDiffAndStore(ids_update_confirm_temp, update_key)
|
||||||
|
if update_diff == false {
|
||||||
|
err = errors.New("update diff error")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data.Delete) > 0 {
|
||||||
|
var ids_delete []string
|
||||||
|
for _, v := range data.Delete {
|
||||||
|
ids_delete = append(ids_delete, strconv.Itoa(int(v.ID)))
|
||||||
|
}
|
||||||
|
del_key := device + "_sync_user_ids_delete_confirm"
|
||||||
|
isSuccess := worker.SetRedisSetAddBatchWithExpire(del_key, ids_delete, time.Second*30)
|
||||||
|
if !isSuccess {
|
||||||
|
err = errors.New("set del confirm error")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//待确认集合暂存
|
||||||
|
ids_delete_confirm_temp := device + "_sync_user_ids_delete_confirm_temp"
|
||||||
|
delete_diff := worker.SetRedisSetDiffAndStore(ids_delete_confirm_temp, del_key)
|
||||||
|
if delete_diff == false {
|
||||||
|
err = errors.New("delete diff error")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成新的token,存入redis,返回信息
|
||||||
|
func CreateTokenAndSave(user dao.User) (string, error) {
|
||||||
|
var tokenString string
|
||||||
|
var err error
|
||||||
|
key := "user_" + user.Name
|
||||||
|
redis_token := worker.GetRedis(string(key))
|
||||||
|
if redis_token == "" {
|
||||||
|
// 生成 JWT 令牌
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||||
|
"username": user.Name,
|
||||||
|
"id": user.ID,
|
||||||
|
"exp": time.Now().Add(time.Hour * 10).Unix(), // 令牌过期时间, 10小时后过期
|
||||||
|
})
|
||||||
|
tokenString, err = token.SignedString(proto.SigningKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
worker.SetRedisWithExpire("user_"+user.Name, tokenString, time.Hour*10) // 将用户信息存入
|
||||||
|
worker.SetRedisWithExpire(tokenString, tokenString, time.Hour*10) // 设置过期时间为10分钟
|
||||||
|
data := make(map[string]interface{})
|
||||||
|
data["id"] = user.ID
|
||||||
|
data["username"] = user.Name
|
||||||
|
data["email"] = user.Email
|
||||||
|
worker.SetHash(tokenString, data) // 将用户信息存入
|
||||||
|
} else {
|
||||||
|
tokenString = redis_token
|
||||||
|
}
|
||||||
|
// 返回令牌
|
||||||
|
return tokenString, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户信息,有redis缓存
|
||||||
|
func GetUserByIDFromUserCenter(id int) dao.User {
|
||||||
|
if id <= 0 {
|
||||||
|
return dao.User{}
|
||||||
|
}
|
||||||
|
var user dao.User
|
||||||
|
//先从redis获取
|
||||||
|
key := "user_info_" + strconv.Itoa(id)
|
||||||
|
userStr := worker.GetRedis(key)
|
||||||
|
//log.Println("user_str:", userStr)
|
||||||
|
if userStr != "" {
|
||||||
|
err := json.Unmarshal([]byte(userStr), &user)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("get user info , json unmarshal error:", err, "\tuser_str:", userStr)
|
||||||
|
return dao.User{}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
user = GetUserInfoByIDFromUserCenterHttp(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{}
|
||||||
|
}
|
||||||
|
userStr = string(userJson)
|
||||||
|
success := worker.SetRedisWithExpire(key, userStr, time.Second*10)
|
||||||
|
if !success {
|
||||||
|
fmt.Println("set redis error,user json:", userStr)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Println("GetUserByIDFromUserCenter user not found, id:", id)
|
||||||
|
log.Println("response user:", user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserInfoResponse struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data dao.User `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUserInfoByIDFromUserCenterHttp(id int) dao.User {
|
||||||
|
var resp UserInfoResponse
|
||||||
|
url := "https://uc.ljsea.top/user/info?super_id=1"
|
||||||
|
tokens := worker.GetRedisSetMembers("super_permission_tokens")
|
||||||
|
if len(tokens) == 0 {
|
||||||
|
return resp.Data
|
||||||
|
}
|
||||||
|
token := tokens[0]
|
||||||
|
//请求参数
|
||||||
|
req := map[string]int{
|
||||||
|
"id": id,
|
||||||
|
}
|
||||||
|
headers := map[string]string{
|
||||||
|
"token": token,
|
||||||
|
}
|
||||||
|
reqByte, _ := json.Marshal(req)
|
||||||
|
err, respBytes := worker.DoPostRequestJSON(url, reqByte, headers)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("GetUserInfoByIDFromUserCenterHttp error:", err)
|
||||||
|
return resp.Data
|
||||||
|
}
|
||||||
|
if err2 := json.Unmarshal(respBytes, &resp); err2 != nil {
|
||||||
|
log.Println("GetUserInfoByIDFromUserCenterHttp json unmarshal error:", err2)
|
||||||
|
}
|
||||||
|
if resp.Data.ID == 0 {
|
||||||
|
log.Println("GetUserInfoByIDFromUserCenterHttp user not found, resp:", string(respBytes))
|
||||||
|
return resp.Data
|
||||||
|
}
|
||||||
|
return resp.Data
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"videoplayer/dao"
|
"videoplayer/dao"
|
||||||
"videoplayer/proto"
|
"videoplayer/proto"
|
||||||
|
"videoplayer/worker"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetVideo(id, auth_id int) dao.Video {
|
func GetVideo(id, auth_id int) dao.Video {
|
||||||
|
|
@ -16,7 +19,15 @@ func GetWillDelVideoList(id int) []dao.Video {
|
||||||
return dao.FindWillDelVideoList(id)
|
return dao.FindWillDelVideoList(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetVideoList(auth_id int, start, end, hour string) []dao.Video {
|
func GetVideoList(auth_id, id int, start, end, hour string) []dao.Video {
|
||||||
|
if id > 0 {
|
||||||
|
user := dao.FindUserByID2(auth_id)
|
||||||
|
if user.Role == "admin" {
|
||||||
|
return dao.FindVideoByID2(id) //可根据id查找视频
|
||||||
|
} else {
|
||||||
|
return []dao.Video{dao.FindVideoByID(id, auth_id)}
|
||||||
|
}
|
||||||
|
}
|
||||||
if start == "" {
|
if start == "" {
|
||||||
return dao.FindVideoListsByAuthID(auth_id)
|
return dao.FindVideoListsByAuthID(auth_id)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -59,8 +70,16 @@ func GetVideoListByPage(auth_id, page, page_size int) []dao.Video {
|
||||||
return dao.GetVideoListByPage(auth_id, page, page_size)
|
return dao.GetVideoListByPage(auth_id, page, page_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteVideo(id, user int) int {
|
func DeleteVideo(id, user int, tp string) int {
|
||||||
return dao.DeleteVideoByID(id, user)
|
if tp == "del_with_logic" {
|
||||||
|
data := map[string]interface{}{"id": id, "auth_id": user, "delete_time": time.Now().Format("2006-01-02 15:04:05"), "method": "delete"}
|
||||||
|
str, _ := json.Marshal(data)
|
||||||
|
SetVideoOption("user-"+strconv.Itoa(user)+"-option", string(str))
|
||||||
|
return dao.LogicDeleteVideoByID(id, user)
|
||||||
|
} else if tp == "del_with_real" {
|
||||||
|
return dao.DeleteVideoByID(id, user)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func QuashVideo(user int, data map[string]interface{}) (int, string) {
|
func QuashVideo(user int, data map[string]interface{}) (int, string) {
|
||||||
|
|
@ -73,6 +92,14 @@ func QuashVideo(user int, data map[string]interface{}) (int, string) {
|
||||||
}()
|
}()
|
||||||
switch data["method"] {
|
switch data["method"] {
|
||||||
case "delete":
|
case "delete":
|
||||||
|
video_id := int(data["id"].(float64))
|
||||||
|
res = dao.RollbackVideoByID(video_id, user)
|
||||||
|
if res == 0 {
|
||||||
|
msg = strconv.Itoa(video_id) + " rollback video error"
|
||||||
|
} else {
|
||||||
|
res = 0
|
||||||
|
msg = "success"
|
||||||
|
}
|
||||||
case "delay":
|
case "delay":
|
||||||
if data["option"] == "all" {
|
if data["option"] == "all" {
|
||||||
if dao.QuashAllDelay(user, data["delay_day"].(int)) == 0 {
|
if dao.QuashAllDelay(user, data["delay_day"].(int)) == 0 {
|
||||||
|
|
@ -106,29 +133,15 @@ func UpdateVideo(videoPath, videoName string, cameraID, videoID, authID, human,
|
||||||
if video.ID == 0 {
|
if video.ID == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if videoPath == "" {
|
|
||||||
videoPath = video.VideoPath
|
|
||||||
}
|
|
||||||
if videoName == "" {
|
|
||||||
videoName = video.VideoName
|
|
||||||
}
|
|
||||||
if cameraID == 0 {
|
|
||||||
cameraID = video.CameraID
|
|
||||||
}
|
|
||||||
if human == 0 {
|
|
||||||
human = video.Human
|
|
||||||
}
|
|
||||||
if isDelete == 0 {
|
|
||||||
isDelete = video.IsDelete
|
|
||||||
}
|
|
||||||
if createTime == "" {
|
|
||||||
createTime = video.CreateTime
|
|
||||||
}
|
|
||||||
if endTime == "" {
|
|
||||||
endTime = video.EndTime
|
|
||||||
}
|
|
||||||
if fileSize == 0 {
|
|
||||||
fileSize = video.FileSize
|
|
||||||
}
|
|
||||||
return dao.UpdateVideo(videoPath, videoName, cameraID, videoID, authID, human, isDelete, createTime, endTime, fileSize)
|
return dao.UpdateVideo(videoPath, videoName, cameraID, videoID, authID, human, isDelete, createTime, endTime, fileSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetVideoOption(key string, value string) {
|
||||||
|
//查看list长度
|
||||||
|
lens := worker.GetRedisListLen(key)
|
||||||
|
if lens > 100 {
|
||||||
|
//移除开头的元素
|
||||||
|
worker.PopRedisList(key)
|
||||||
|
}
|
||||||
|
worker.PushRedisList(key, value)
|
||||||
|
}
|
||||||
|
|
|
||||||
181
worker/redis.go
181
worker/redis.go
|
|
@ -50,7 +50,7 @@ func IsContainKey(key string) bool {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
val, err := RedisClient.Exists(ctx, key).Result() // 检查键是否存在, 如果存在则返回 1, 否则返回 0
|
val, err := RedisClient.Exists(ctx, key).Result() // 检查键是否存在, 如果存在则返回 1, 否则返回 0
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error getting key: %v", err)
|
//fmt.Println("Error getting key: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if val == 0 {
|
if val == 0 {
|
||||||
|
|
@ -71,6 +71,17 @@ func SetRedis(key string, value string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置redis,永久
|
||||||
|
func SetRedisForever(key string, value string) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.Set(ctx, key, value, 0).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// 设置hash
|
// 设置hash
|
||||||
func SetHashWithTime(key string, id int, name, email string, duration time.Duration) bool {
|
func SetHashWithTime(key string, id int, name, email string, duration time.Duration) bool {
|
||||||
//捕获错误,如果错误返回
|
//捕获错误,如果错误返回
|
||||||
|
|
@ -159,12 +170,28 @@ func GetRedis(key string) string {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
val, err := RedisClient.Get(ctx, key).Result() // 从 Redis 读取键值, 如果键不存在则返回空字符串, 如果出现错误则返回错误
|
val, err := RedisClient.Get(ctx, key).Result() // 从 Redis 读取键值, 如果键不存在则返回空字符串, 如果出现错误则返回错误
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(key, " Error getting key: %v", err)
|
//fmt.Println(key, " Error getting key: %v", err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetRedisWithExpire(key string) (string, int) {
|
||||||
|
ctx := context.Background()
|
||||||
|
val, err := RedisClient.Get(ctx, key).Result() // 从 Redis 读取键值, 如果键不存在则返回空字符串, 如果出现错误则返回错误
|
||||||
|
if err != nil {
|
||||||
|
//fmt.Println(key, " Error getting key: %v", err)
|
||||||
|
return "", 0
|
||||||
|
} else {
|
||||||
|
// 获取键的过期时间
|
||||||
|
ttl, err2 := RedisClient.TTL(ctx, key).Result()
|
||||||
|
if err2 != nil {
|
||||||
|
return val, -1
|
||||||
|
}
|
||||||
|
return val, int(ttl.Seconds())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// pop redis list from right,as stack
|
// pop redis list from right,as stack
|
||||||
func PopRedisList(key string) string {
|
func PopRedisList(key string) string {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
@ -205,6 +232,16 @@ func PushRedisList(key string, value string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetRedisListLen(key string) int64 {
|
||||||
|
ctx := context.Background()
|
||||||
|
val, err := RedisClient.LLen(ctx, key).Result()
|
||||||
|
if err != nil {
|
||||||
|
//fmt.Println("Error getting key: %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
func PushRedisListWithExpire(key string, value string, expire time.Duration) bool {
|
func PushRedisListWithExpire(key string, value string, expire time.Duration) bool {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := RedisClient.RPush(ctx, key, value).Err()
|
err := RedisClient.RPush(ctx, key, value).Err()
|
||||||
|
|
@ -260,7 +297,7 @@ func hGetRedis(key string, field string) string {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
val, err := RedisClient.HGet(ctx, key, field).Result()
|
val, err := RedisClient.HGet(ctx, key, field).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error getting key: %v", err)
|
//fmt.Println("Error getting key: %v", err)
|
||||||
}
|
}
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
@ -292,17 +329,34 @@ func SetRedisSetAdd(key string, value string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批量添加元素
|
||||||
|
func SetRedisSetAddBatchWithExpire(key string, values []string, expire time.Duration) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.SAdd(ctx, key, values).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("SetRedisSetAddBatchWithExpire Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
err = RedisClient.Expire(ctx, key, expire).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("SetRedisSetAddBatchWithExpire Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 设置set,添加元素
|
// 设置set,添加元素
|
||||||
func SetRedisSetAddWithExpire(key string, value string, expire time.Duration) bool {
|
func SetRedisSetAddWithExpire(key string, value string, expire time.Duration) bool {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := RedisClient.SAdd(ctx, key, value).Err()
|
err := RedisClient.SAdd(ctx, key, value).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error setting key: %v", err)
|
fmt.Println("SetRedisSetAddWithExpire Error setting key: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
err = RedisClient.Expire(ctx, key, expire).Err()
|
err = RedisClient.Expire(ctx, key, expire).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error setting key: %v", err)
|
fmt.Println("SetRedisSetAddWithExpire Error setting key: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
@ -324,7 +378,7 @@ func GetRedisSetIntersect(key1 string, key2 string) []string {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
val, err := RedisClient.SInter(ctx, key1, key2).Result()
|
val, err := RedisClient.SInter(ctx, key1, key2).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error getting key: %v", err)
|
//fmt.Println("Error getting key: %v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return val
|
return val
|
||||||
|
|
@ -335,7 +389,7 @@ func IsContainSet(key string, value string) bool {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
val, err := RedisClient.SIsMember(ctx, key, value).Result()
|
val, err := RedisClient.SIsMember(ctx, key, value).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error getting key: %v", err)
|
//fmt.Println("Error getting key: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return val
|
return val
|
||||||
|
|
@ -346,7 +400,7 @@ func GetRedisSetMembers(key string) []string {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
val, err := RedisClient.SMembers(ctx, key).Result()
|
val, err := RedisClient.SMembers(ctx, key).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error getting key: %v", err)
|
//fmt.Println("Error getting key: %v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return val
|
return val
|
||||||
|
|
@ -357,7 +411,7 @@ func SetRedisBitmap(key string, offset int64, value int) bool {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := RedisClient.SetBit(ctx, key, offset, value).Err()
|
err := RedisClient.SetBit(ctx, key, offset, value).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error setting key: %v", err)
|
//fmt.Println("Error setting key: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
@ -368,7 +422,7 @@ func GetRedisBitmap(key string, offset int64) int {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
val, err := RedisClient.GetBit(ctx, key, offset).Result()
|
val, err := RedisClient.GetBit(ctx, key, offset).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error getting key: %v", err)
|
//fmt.Println("Error getting key: %v", err)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return int(val)
|
return int(val)
|
||||||
|
|
@ -399,3 +453,110 @@ func Subscribe(channel string) []string {
|
||||||
}
|
}
|
||||||
return messages
|
return messages
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// redis两个set求差集存入第一个set
|
||||||
|
func SetRedisSetDiffAndStore(key1 string, key2 string) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.SDiffStore(ctx, key1, key1, key2).Err() //将key1和key2的差集存入key1
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("SetRedisSetDiffAndStore Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// redis将第二个set存入第一个set
|
||||||
|
func SetRedisSetUnionAndStore(key1 string, key2 string) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.SUnionStore(ctx, key1, key1, key2).Err() //将key1和key2的并集存入key1
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("SetRedisSetUnionAndStore Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// redis 清空set
|
||||||
|
func ClearRedisSet(key string) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.Del(ctx, key).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取两个集合的并集
|
||||||
|
func GetRedisSetUnion(key1 string, key2 string) []string {
|
||||||
|
ctx := context.Background()
|
||||||
|
val, err := RedisClient.SUnion(ctx, key1, key2).Result()
|
||||||
|
if err != nil {
|
||||||
|
//fmt.Println("Error getting key: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
type RedisInfo struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
Type string
|
||||||
|
Expire int // 过期时间, 单位: 秒
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有的key和value,及其对应的过期时间
|
||||||
|
func GetAllRedisInfo() ([]RedisInfo, error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
keys, err := RedisClient.Keys(ctx, "*").Result()
|
||||||
|
if err != nil {
|
||||||
|
//fmt.Println("Error getting key: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var redisInfos []RedisInfo
|
||||||
|
for _, key := range keys {
|
||||||
|
//先查看key类型,再根据类型获取value
|
||||||
|
key_type, val, err := getKeyTypeAndData(key)
|
||||||
|
if err != nil {
|
||||||
|
//fmt.Println("Error getting key: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
expire, err := RedisClient.TTL(ctx, key).Result()
|
||||||
|
if err != nil {
|
||||||
|
//fmt.Println("Error getting key: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
redisInfo := RedisInfo{
|
||||||
|
Key: key,
|
||||||
|
Value: val,
|
||||||
|
Type: key_type,
|
||||||
|
Expire: int(expire.Seconds()),
|
||||||
|
}
|
||||||
|
redisInfos = append(redisInfos, redisInfo)
|
||||||
|
}
|
||||||
|
return redisInfos, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getKeyTypeAndData(key string) (string, string, error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
key_type := RedisClient.Type(ctx, key).Val()
|
||||||
|
var val interface{}
|
||||||
|
var err error
|
||||||
|
switch key_type {
|
||||||
|
case "string":
|
||||||
|
val, err = RedisClient.Get(ctx, key).Result()
|
||||||
|
case "hash":
|
||||||
|
val, err = RedisClient.HGetAll(ctx, key).Result()
|
||||||
|
case "list":
|
||||||
|
val, err = RedisClient.LRange(ctx, key, 0, -1).Result()
|
||||||
|
case "set":
|
||||||
|
val, err = RedisClient.SMembers(ctx, key).Result()
|
||||||
|
case "zset":
|
||||||
|
val, err = RedisClient.ZRange(ctx, key, 0, -1).Result()
|
||||||
|
case "bitmap":
|
||||||
|
val, err = RedisClient.GetBit(ctx, key, 0).Result()
|
||||||
|
default:
|
||||||
|
val = "unknown type"
|
||||||
|
}
|
||||||
|
return key_type, fmt.Sprintf("%v", val), err
|
||||||
|
}
|
||||||
|
|
|
||||||
419
worker/req.go
419
worker/req.go
|
|
@ -3,10 +3,17 @@ package worker
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"videoplayer/dao"
|
||||||
|
"videoplayer/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
var client *http.Client
|
var client *http.Client
|
||||||
|
|
@ -80,3 +87,415 @@ func GenerateCompletion(url, prompt string, model string) (map[string]interface{
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取同步数据通用方法
|
||||||
|
func SyncDataFromMasterReq(url string, token string) proto.UserSync {
|
||||||
|
//从接口获取数据
|
||||||
|
req, err := http.NewRequest("POST", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return proto.UserSync{}
|
||||||
|
}
|
||||||
|
req.Header.Set("token", token)
|
||||||
|
//json负载
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
//传输数据
|
||||||
|
m := make(map[string]interface{})
|
||||||
|
m["token"] = token
|
||||||
|
m["device"] = ""
|
||||||
|
|
||||||
|
if client == nil {
|
||||||
|
client = &http.Client{}
|
||||||
|
}
|
||||||
|
client = &http.Client{}
|
||||||
|
//获取数据
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return proto.UserSync{}
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return proto.UserSync{}
|
||||||
|
}
|
||||||
|
var result map[string]interface{}
|
||||||
|
err = json.Unmarshal(body, &result)
|
||||||
|
if err != nil {
|
||||||
|
return proto.UserSync{}
|
||||||
|
}
|
||||||
|
fmt.Println("SyncDataFromMasterReq result:", result)
|
||||||
|
if result["code"].(float64) != 0 {
|
||||||
|
return proto.UserSync{}
|
||||||
|
}
|
||||||
|
var userSync proto.UserSync
|
||||||
|
err = json.Unmarshal([]byte(result["data"].(string)), &userSync)
|
||||||
|
if err != nil {
|
||||||
|
return proto.UserSync{}
|
||||||
|
}
|
||||||
|
return userSync
|
||||||
|
}
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data proto.UserSync `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShellResponse struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data []dao.Shell `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShellResponseV2 struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data []proto.UpdateShellRespV2 `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取数据,全量及增量
|
||||||
|
func SyncDataFromMasterReq2(url string, data proto.SyncUserReq) (proto.UserSync, error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
fmt.Println("SyncDataFromMasterReq2 error:", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var res proto.UserSync
|
||||||
|
//从接口获取数据
|
||||||
|
json_data, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(json_data))
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
//传输数据
|
||||||
|
if client == nil {
|
||||||
|
client = &http.Client{}
|
||||||
|
}
|
||||||
|
//获取数据
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
//解析数据
|
||||||
|
responseBod, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
var response Response
|
||||||
|
err = json.Unmarshal(responseBod, &response)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
res = response.Data
|
||||||
|
fmt.Println("SyncDataFromMasterReq2 result add data:", len(res.Add), "update data:", len(res.Update), "delete data:", len(res.Delete))
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取待执行的shell
|
||||||
|
func SyncDataFromMasterShellReq2(url string, data proto.SyncUserShellReq) ([]dao.Shell, error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
fmt.Println("SyncDataFromMasterReq2 error:", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var res []dao.Shell
|
||||||
|
//从接口获取数据
|
||||||
|
json_data, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(json_data))
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("token", data.Token)
|
||||||
|
//传输数据
|
||||||
|
if client == nil {
|
||||||
|
client = &http.Client{}
|
||||||
|
}
|
||||||
|
//获取数据
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
//解析数据
|
||||||
|
responseBod, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
var response ShellResponse
|
||||||
|
err = json.Unmarshal(responseBod, &response)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
res = response.Data
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取待执行的shell
|
||||||
|
func SyncDataFromMasterShellReq3(url string, data proto.SyncUserShellResp) ([]proto.UpdateShellRespV2, error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
fmt.Println("SyncDataFromMasterReq2 error:", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var res []proto.UpdateShellRespV2
|
||||||
|
//从接口获取数据
|
||||||
|
json_data, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(json_data))
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("token", data.Token)
|
||||||
|
//传输数据
|
||||||
|
if client == nil {
|
||||||
|
client = &http.Client{}
|
||||||
|
}
|
||||||
|
//获取数据
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
//解析数据
|
||||||
|
responseBod, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
var response ShellResponseV2
|
||||||
|
err = json.Unmarshal(responseBod, &response)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
res = response.Data
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DoPostRequestJSON(url string, jsonData []byte, headers map[string]string) (error, []byte) {
|
||||||
|
httpClient := &http.Client{}
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
fmt.Println("SyncDataFromMasterReq2 error:", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
//从接口获取数据
|
||||||
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
|
||||||
|
if err != nil {
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0")
|
||||||
|
//设置header
|
||||||
|
for k, v := range headers {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
//传输数据
|
||||||
|
if httpClient == nil {
|
||||||
|
httpClient = &http.Client{}
|
||||||
|
}
|
||||||
|
//获取数据
|
||||||
|
resp, err := httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
//解析数据
|
||||||
|
responseBod, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
return err, responseBod
|
||||||
|
}
|
||||||
|
|
||||||
|
func DoPostRequestForm(url string, jsonData []byte, headers map[string]string) (error, []byte) {
|
||||||
|
httpClient := &http.Client{}
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
fmt.Println("SyncDataFromMasterReq2 error:", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 创建一个新的 buffer 用于存储 multipart/form-data 请求体
|
||||||
|
body := &bytes.Buffer{}
|
||||||
|
writer := multipart.NewWriter(body)
|
||||||
|
// 修改 data 类型为 map[string]interface{} 以支持不同类型的值
|
||||||
|
var data map[string]interface{}
|
||||||
|
err2 := json.Unmarshal(jsonData, &data)
|
||||||
|
if err2 != nil {
|
||||||
|
log.Println("do post json unmarshal error:", err2)
|
||||||
|
return err2, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for k, v := range data {
|
||||||
|
switch val := v.(type) {
|
||||||
|
case bool:
|
||||||
|
// 处理布尔类型的值
|
||||||
|
err = writer.WriteField(k, strconv.FormatBool(val))
|
||||||
|
case string:
|
||||||
|
// 处理字符串类型的值
|
||||||
|
err = writer.WriteField(k, val)
|
||||||
|
default:
|
||||||
|
// 其他类型可以根据需要扩展处理逻辑
|
||||||
|
log.Printf("Unsupported type for field %s: %T\n", k, v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Println("write field error:", err)
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭 writer 以完成请求体的构建
|
||||||
|
err = writer.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建 POST 请求
|
||||||
|
req, err := http.NewRequest("POST", url, body)
|
||||||
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0")
|
||||||
|
if err != nil {
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置 Content-Type 为 multipart/form-data,并带上 boundary
|
||||||
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
|
||||||
|
// 设置其他自定义请求头
|
||||||
|
for k, v := range headers {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
resp, err := httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// 读取响应体
|
||||||
|
responseBod, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, responseBod
|
||||||
|
}
|
||||||
|
|
||||||
|
func DoPostRequestFormUrlEncoded(url_ string, jsonData []byte, headers map[string]string) (error, []byte) {
|
||||||
|
httpClient := &http.Client{}
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
log.Println("SyncDataFromMasterReq2 error:", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 解析 JSON 数据
|
||||||
|
var data map[string]interface{}
|
||||||
|
err := json.Unmarshal(jsonData, &data)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("do post json unmarshal error:", err)
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建 url.Values 来存储请求参数
|
||||||
|
reqData := url.Values{}
|
||||||
|
for k, v := range data {
|
||||||
|
switch val := v.(type) {
|
||||||
|
case bool:
|
||||||
|
// 处理布尔类型的值
|
||||||
|
reqData.Set(k, strconv.FormatBool(val))
|
||||||
|
case string:
|
||||||
|
// 处理字符串类型的值
|
||||||
|
reqData.Set(k, val)
|
||||||
|
default:
|
||||||
|
// 其他类型可以根据需要扩展处理逻辑
|
||||||
|
log.Printf("Unsupported type for field %s: %T\n", k, v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 url.Values 编码为 URL 编码的格式
|
||||||
|
encodedData := reqData.Encode()
|
||||||
|
|
||||||
|
// 创建 POST 请求
|
||||||
|
req, err := http.NewRequest("POST", url_, bytes.NewBufferString(encodedData))
|
||||||
|
if err != nil {
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置请求头
|
||||||
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0")
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
|
||||||
|
// 设置其他自定义请求头
|
||||||
|
for k, v := range headers {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
resp, err := httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// 读取响应体
|
||||||
|
responseBod, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, responseBod
|
||||||
|
}
|
||||||
|
|
||||||
|
func DoGetRequest(url string, headers map[string]string) (error, []byte) {
|
||||||
|
httpClient := &http.Client{}
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
fmt.Println("SyncDataFromMasterReq2 error:", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
//从接口获取数据
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0")
|
||||||
|
if err != nil {
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
//设置header
|
||||||
|
for k, v := range headers {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
//传输数据
|
||||||
|
if httpClient == nil {
|
||||||
|
httpClient = &http.Client{}
|
||||||
|
}
|
||||||
|
//获取数据
|
||||||
|
resp, err := httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
//解析数据
|
||||||
|
responseBod, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
return err, responseBod
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
package worker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
mrand "math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetRandomString(l int) string {
|
||||||
|
str := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
bytes := []byte(str)
|
||||||
|
var result []byte
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
result = append(result, bytes[mrand.Intn(len(bytes))])
|
||||||
|
}
|
||||||
|
return string(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCurrentTimestamp() int64 {
|
||||||
|
// 获取当前时间戳
|
||||||
|
return time.Now().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AESEncrypt 函数使用AES-GCM算法对明文进行加密
|
||||||
|
func AESEncrypt(plaintext []byte, key []byte) (string, error) {
|
||||||
|
// 创建AES加密块
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建GCM模式的加密器
|
||||||
|
gcm, err := cipher.NewGCM(block)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成随机的nonce
|
||||||
|
nonce := make([]byte, gcm.NonceSize())
|
||||||
|
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行加密操作
|
||||||
|
ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)
|
||||||
|
|
||||||
|
// 将加密结果转换为Base64编码字符串
|
||||||
|
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AESDecrypt 函数使用AES-GCM算法对密文进行解密
|
||||||
|
func AESDecrypt(ciphertext string, key []byte) ([]byte, error) {
|
||||||
|
// 将Base64编码的密文转换为字节切片
|
||||||
|
data, err := base64.StdEncoding.DecodeString(ciphertext)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建AES加密块
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建GCM模式的解密器
|
||||||
|
gcm, err := cipher.NewGCM(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取nonce和真正的密文
|
||||||
|
nonceSize := gcm.NonceSize()
|
||||||
|
if len(data) < nonceSize {
|
||||||
|
return nil, fmt.Errorf("密文长度过短")
|
||||||
|
}
|
||||||
|
nonce, ciphertextBytes := data[:nonceSize], data[nonceSize:]
|
||||||
|
|
||||||
|
// 执行解密操作
|
||||||
|
return gcm.Open(nil, nonce, ciphertextBytes, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateMD5(secretKey string) string {
|
||||||
|
hasher := md5.New()
|
||||||
|
hasher.Write([]byte(secretKey))
|
||||||
|
return hex.EncodeToString(hasher.Sum(nil)) // 将二进制数据转换为十六进制字符串
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue