大学生学业作品AI生成工具开发,项目框架
This commit is contained in:
commit
7741066aeb
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="Go" enabled="true" />
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/StuAcaWorksAI.iml" filepath="$PROJECT_DIR$/.idea/StuAcaWorksAI.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"StuAcaWorksAI/proto"
|
||||||
|
"fmt"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/driver/postgres"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DB *gorm.DB
|
||||||
|
|
||||||
|
func Init() error {
|
||||||
|
var db *gorm.DB
|
||||||
|
var err error
|
||||||
|
var dsn string
|
||||||
|
if proto.Config.DB == 0 {
|
||||||
|
dsn = proto.Config.MYSQL_DSN
|
||||||
|
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
} else if proto.Config.DB == 1 {
|
||||||
|
dsn = proto.Config.PG_DSN
|
||||||
|
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to connect database")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = db.AutoMigrate(&User{})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("user table:", err)
|
||||||
|
return err
|
||||||
|
} // 自动迁移,创建表,如果表已经存在,会自动更新表结构,不会删除表,只会创建不存在的表
|
||||||
|
err = db.AutoMigrate(&File{})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("file table:", 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
|
||||||
|
}
|
||||||
|
DB = db
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func Close() {
|
||||||
|
sqlDB, err := DB.DB()
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to connect database")
|
||||||
|
}
|
||||||
|
sqlDB.Close()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,179 @@
|
||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"StuAcaWorksAI/proto"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
gorm.Model
|
||||||
|
// 存储文件名
|
||||||
|
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"`
|
||||||
|
FileSize int `gorm:"column:file_size"`
|
||||||
|
FileType string `gorm:"column:file_type"`
|
||||||
|
FilePath string `gorm:"column:file_path"`
|
||||||
|
AuthID int `gorm:"column:auth_id"`
|
||||||
|
Md5 string `gorm:"column:md5;type:varchar(255);uniqueIndex:idx_file_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileAuth struct {
|
||||||
|
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)
|
||||||
|
if result.Error != nil {
|
||||||
|
return File{}
|
||||||
|
}
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteFileByID(id, user int) bool {
|
||||||
|
res := DB.Model(&File{}).Where("id = ? and auth_id = ?", id, user).Delete(&File{})
|
||||||
|
if res.Error != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindFileByID(id, auth_id int) File {
|
||||||
|
var file File
|
||||||
|
DB.Where("id = ? and auth_id = ?", id, auth_id).First(&file)
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindFileByNames(fileName string, auth_id int) File {
|
||||||
|
var file File
|
||||||
|
DB.Where("file_name = ? and auth_id = ?", fileName, auth_id).First(&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 {
|
||||||
|
var files []File
|
||||||
|
DB.Where("auth_id = ?", auth_id).Find(&files)
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateFileByID(id, auth_id int, fileStoreName, fileName, fileType, filePath string, fileSize int) bool {
|
||||||
|
pd := FindFileByID(id, auth_id)
|
||||||
|
if pd.ID == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
result := DB.Model(&File{}).Where("id = ? and auth_id = ?", id, auth_id).Updates(File{FileStoreName: fileStoreName, FileName: fileName, FileType: fileType, FilePath: filePath, FileSize: fileSize})
|
||||||
|
if result.Error != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteFileByAuthID(auth_id int) bool {
|
||||||
|
res := DB.Model(&File{}).Where("auth_id = ?", auth_id).Delete(&File{})
|
||||||
|
if res.Error != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteFileById(id int) bool {
|
||||||
|
res := DB.Model(&File{}).Where("id = ?", id).Delete(&File{})
|
||||||
|
if res.Error != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
gorm.Model
|
||||||
|
Url string `gorm:"column:url"`
|
||||||
|
IP string `gorm:"column:ip"`
|
||||||
|
Method string `gorm:"column:method"`
|
||||||
|
Params string `gorm:"column:params"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertLogToDB(url, ip, method, params string) uint {
|
||||||
|
logger := Logger{Url: url, IP: ip, Method: method, Params: params}
|
||||||
|
DB.Create(&logger)
|
||||||
|
if logger.ID == 0 {
|
||||||
|
fmt.Println("InsertLogToDB error")
|
||||||
|
}
|
||||||
|
return logger.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteByID(id int) bool {
|
||||||
|
DB.Where("ID = ?", id).Delete(&Logger{})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除3天前的日志
|
||||||
|
func DeleteLog(days int) bool {
|
||||||
|
res := DB.Exec("delete from loggers where created_at < DATE_SUB(CURDATE(), INTERVAL ? DAY)", days)
|
||||||
|
if res.Error != nil {
|
||||||
|
fmt.Println("DeleteLog error", res.Error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,167 @@
|
||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"StuAcaWorksAI/proto"
|
||||||
|
"fmt"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
gorm.Model
|
||||||
|
Name string `gorm:"column:name"`
|
||||||
|
Age int `gorm:"column:age"`
|
||||||
|
Email string `gorm:"column:email"`
|
||||||
|
Password string `gorm:"column:password"`
|
||||||
|
Gender string `gorm:"column:gender"`
|
||||||
|
Role string `gorm:"column:role"`
|
||||||
|
Redis bool `gorm:"column:redis"`
|
||||||
|
Run bool `gorm:"column:run"`
|
||||||
|
Upload bool `gorm:"column:upload"`
|
||||||
|
VideoFunc bool `gorm:"column:video_func"` //视频功能
|
||||||
|
DeviceFunc bool `gorm:"column:device_func"` //设备功能
|
||||||
|
CIDFunc bool `gorm:"column:cid_func"` //持续集成功能
|
||||||
|
Avatar string `gorm:"column:avatar"`
|
||||||
|
CreateTime string `gorm:"column:create_time"`
|
||||||
|
UpdateTime string `gorm:"column:update_time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateUser(name, password, email, gender string, age int) uint {
|
||||||
|
user := User{Name: name, Email: email, Password: password, Gender: gender, Age: age}
|
||||||
|
res := DB.Create(&user)
|
||||||
|
if res.Error != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return user.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteUserByID(id int) int {
|
||||||
|
res := DB.Delete(&User{}, id)
|
||||||
|
if res.Error != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindUserByID(id int) []proto.User {
|
||||||
|
var users []proto.User
|
||||||
|
DB.Where("id = ?", id).First(&users)
|
||||||
|
return users
|
||||||
|
}
|
||||||
|
func FindUserByID2(id int) User {
|
||||||
|
var user User
|
||||||
|
DB.Where("id = ?", id).First(&user)
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindUserByUserID(id int) User {
|
||||||
|
var user User
|
||||||
|
DB.Where("id = ?", id).First(&user)
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindUserByName(name string) User {
|
||||||
|
var user User
|
||||||
|
fmt.Println("name:", name)
|
||||||
|
DB.Where("name = ?", name).First(&user)
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据name模糊查询,邮箱也是,不查询密码
|
||||||
|
func FindUserByNameLike(name string) []proto.User {
|
||||||
|
var users []proto.User
|
||||||
|
DB.Where("name LIKE ? OR email LIKE ?", "%"+name+"%", "%"+name+"%").Find(&users).Limit(32)
|
||||||
|
return users
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindUserByEmail(email string) User {
|
||||||
|
var user User
|
||||||
|
DB.Where("email = ?", email).First(&user)
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateUserByID(id int, name, password, email string) {
|
||||||
|
DB.Model(&User{}).Where("id = ?", id).Updates(User{Name: name, Password: password, Email: email})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 管理员修改用户信息
|
||||||
|
func UpdateUserByID2(id int, req proto.UpdateUserInfoReq) error {
|
||||||
|
updateData := make(map[string]interface{})
|
||||||
|
updateData["Name"] = req.Username
|
||||||
|
updateData["Age"] = req.Age
|
||||||
|
updateData["Role"] = req.Role
|
||||||
|
updateData["Run"] = req.Run
|
||||||
|
updateData["Redis"] = req.Redis
|
||||||
|
updateData["Upload"] = req.Upload
|
||||||
|
updateData["VideoFunc"] = req.VideoFunc
|
||||||
|
updateData["DeviceFunc"] = req.DeviceFunc
|
||||||
|
updateData["CIDFunc"] = req.CIDFunc
|
||||||
|
updateData["Avatar"] = req.Avatar
|
||||||
|
updateData["Gender"] = req.Gender
|
||||||
|
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) error {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
module StuAcaWorksAI
|
||||||
|
|
||||||
|
go 1.23
|
||||||
|
|
||||||
|
toolchain go1.23.7
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gin-gonic/gin v1.10.0
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
|
gorm.io/driver/mysql v1.5.7
|
||||||
|
gorm.io/driver/postgres v1.5.11
|
||||||
|
gorm.io/gorm v1.25.12
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/bytedance/sonic v1.11.6 // indirect
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||||
|
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||||
|
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||||
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5 // indirect
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||||
|
github.com/kr/text v0.2.0 // indirect
|
||||||
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
|
golang.org/x/arch v0.8.0 // indirect
|
||||||
|
golang.org/x/crypto v0.23.0 // indirect
|
||||||
|
golang.org/x/net v0.25.0 // indirect
|
||||||
|
golang.org/x/sync v0.1.0 // indirect
|
||||||
|
golang.org/x/sys v0.26.0 // indirect
|
||||||
|
golang.org/x/text v0.15.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.34.1 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,144 @@
|
||||||
|
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||||
|
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||||
|
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
|
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||||
|
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
|
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||||
|
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||||
|
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
|
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||||
|
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
|
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
|
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
|
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||||
|
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
|
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||||
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||||
|
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||||
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||||
|
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||||
|
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||||
|
gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314=
|
||||||
|
gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
|
||||||
|
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
|
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||||
|
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||||
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
//"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 跨域访问:cross origin resource share
|
||||||
|
func CrosHandler() gin.HandlerFunc {
|
||||||
|
return func(context *gin.Context) {
|
||||||
|
//method := context.Request.Method
|
||||||
|
context.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
context.Header("Access-Control-Allow-Origin", "*") // 设置允许访问所有域
|
||||||
|
context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
|
||||||
|
context.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma,token,openid,opentoken")
|
||||||
|
context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")
|
||||||
|
context.Header("Access-Control-Max-Age", "172800")
|
||||||
|
context.Header("Access-Control-Allow-Credentials", "false")
|
||||||
|
context.Set("content-type", "application/json") //设置返回格式是json
|
||||||
|
|
||||||
|
// if method == "OPTIONS" {
|
||||||
|
// context.JSON(http.StatusOK, gin.H{
|
||||||
|
// "code":1,
|
||||||
|
// "message":"error",
|
||||||
|
// "data":"request error",
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
//处理请求
|
||||||
|
context.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,194 @@
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"StuAcaWorksAI/dao"
|
||||||
|
"StuAcaWorksAI/proto"
|
||||||
|
"StuAcaWorksAI/service"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
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,405 @@
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"StuAcaWorksAI/dao"
|
||||||
|
"StuAcaWorksAI/proto"
|
||||||
|
"StuAcaWorksAI/service"
|
||||||
|
"StuAcaWorksAI/worker"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SetRedisReq struct {
|
||||||
|
Option string `json:"option" form:"option"`
|
||||||
|
Key string `json:"key" form:"key"`
|
||||||
|
Value string `json:"value" form:"value"`
|
||||||
|
Expire int `json:"expire" form:"expire"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetDeviceStatusReq struct {
|
||||||
|
ID string `json:"id" form:"id"` //设备编码
|
||||||
|
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) {
|
||||||
|
toolGroup := router.Group("/tool")
|
||||||
|
toolGroup.POST("/set_redis", SetRedis)
|
||||||
|
toolGroup.POST("/get_redis", GetRedis)
|
||||||
|
|
||||||
|
//文件上传、下载
|
||||||
|
toolGroup.POST("/upload", UploadFile)
|
||||||
|
toolGroup.GET("/download", DownloadFile)
|
||||||
|
toolGroup.GET("/file/:filename", GetFile)
|
||||||
|
toolGroup.POST("/file_list", GetFileList)
|
||||||
|
//文件管理
|
||||||
|
toolGroup.POST("/file_del", DelFile)
|
||||||
|
//服务器、设备状态接口
|
||||||
|
toolGroup.POST("/monitor", SetDeviceStatusV2)
|
||||||
|
//发送邮件
|
||||||
|
toolGroup.POST("/send_mail", SendMailTool)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetDeviceStatusV2(c *gin.Context) {
|
||||||
|
// TODO
|
||||||
|
var req SetDeviceStatusReq
|
||||||
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
|
c.JSON(200, gin.H{"code": 400, "message": "参数错误"})
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
token := c.Request.Header.Get("token")
|
||||||
|
if token == "" {
|
||||||
|
c.JSON(200, gin.H{"code": 401, "message": "token为空"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
devices := worker.GetRedisSetMembers(token)
|
||||||
|
if len(devices) == 0 {
|
||||||
|
c.JSON(200, gin.H{"code": 402, "message": "设备为空"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, v := range devices {
|
||||||
|
if v == req.ID {
|
||||||
|
// 继续处理请求
|
||||||
|
//是否是暂停之后第一次上线,如果是则发送邮件通知
|
||||||
|
device_status := worker.GetRedis("monitor_" + req.ID)
|
||||||
|
isExist := worker.IsContainKey("monitor_" + req.ID)
|
||||||
|
if device_status == "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)
|
||||||
|
c.JSON(200, gin.H{"code": 0, "message": "success"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.JSON(200, gin.H{"code": 402, "message": "设备不存在"})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
//先查看是否有权限
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
id1 := int(id.(float64))
|
||||||
|
|
||||||
|
file_id, _ := strconv.Atoi(c.PostForm("id"))
|
||||||
|
|
||||||
|
file_ := dao.FindFileByID(file_id, id1)
|
||||||
|
if file_.ID == 0 {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "file not found", "code": proto.FileNotFound, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//删除文件
|
||||||
|
err := os.Remove(file_.FilePath + "/" + file_.FileStoreName)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "delete file failed", "code": proto.DeleteFileFailed, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//删除文件信息
|
||||||
|
if res := dao.DeleteFileById(file_id); !res {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "delete file info failed", "code": proto.DeleteFileInfoFailed, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": proto.SuccessCode, "message": "success"})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
//先查看是否有权限
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
id1 := int(id.(float64))
|
||||||
|
//从请求头获取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})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownloadFile(c *gin.Context) {
|
||||||
|
//参数
|
||||||
|
//filename := c.Param("filename")
|
||||||
|
file_id, _ := strconv.Atoi(c.Query("id"))
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
//查询文件信息
|
||||||
|
//file := dao.FindFileByNames(file_id, int(id.(float64)))
|
||||||
|
file_ := dao.FindFileByID(file_id, int(id.(float64)))
|
||||||
|
if file_.ID == 0 {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "file not found", "code": proto.FileNotFound, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//下载文件
|
||||||
|
// 打开文件
|
||||||
|
file, err := os.Open(file_.FilePath + "/" + file_.FileStoreName)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal Server Error", "message": "Failed to open file"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// 设置响应头
|
||||||
|
c.Writer.Header().Set("Content-Type", "application/octet-stream")
|
||||||
|
c.Writer.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", file_.FileName))
|
||||||
|
|
||||||
|
// 发送文件内容
|
||||||
|
_, err = io.Copy(c.Writer, file)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal Server Error", "message": "Failed to send file"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Status(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetRedis(c *gin.Context) {
|
||||||
|
//先查看是否有权限
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
id1 := int(id.(float64))
|
||||||
|
user := dao.FindUserByUserID(id1)
|
||||||
|
if user.Redis == false {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "no redis Permissions", "code": proto.NoRedisPermissions, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//解析请求参数
|
||||||
|
var req SetRedisReq
|
||||||
|
if err := c.ShouldBind(&req); err == nil {
|
||||||
|
var code int
|
||||||
|
var message string
|
||||||
|
if req.Option == "list" {
|
||||||
|
code, message = service.SetToolRedisList(req.Key, req.Value, req.Expire)
|
||||||
|
} else if req.Option == "set" {
|
||||||
|
code, message = service.SetToolRedisSet(req.Key, req.Value, req.Expire)
|
||||||
|
} else if req.Option == "kv" {
|
||||||
|
code, message = service.SetToolRedisKV(req.Key, req.Value, req.Expire)
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"code": code, "message": message})
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRedis(c *gin.Context) {
|
||||||
|
//先查看是否有权限
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
id1 := int(id.(float64))
|
||||||
|
user := dao.FindUserByUserID(id1)
|
||||||
|
if user.Redis == false {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "no redis Permissions", "code": proto.NoRedisPermissions, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//解析请求参数
|
||||||
|
var req SetRedisReq
|
||||||
|
if err := c.ShouldBind(&req); err == nil {
|
||||||
|
if req.Option == "one" {
|
||||||
|
code, message := service.GetToolRedis(req.Key)
|
||||||
|
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 {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"error": "parameter error", "code": proto.ParameterError, "message": "failed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 服务器、设备状态扫描
|
||||||
|
func ScanDeviceStatus() {
|
||||||
|
// TODO
|
||||||
|
// 检查设备状态
|
||||||
|
// 如果设备状态异常, 则发送邮件通知
|
||||||
|
devices := worker.GetRedisSetMembers("627gyf3488h")
|
||||||
|
offline := ""
|
||||||
|
for _, v := range devices {
|
||||||
|
c := worker.IsContainKey("monitor_" + v)
|
||||||
|
if c == false {
|
||||||
|
worker.SetRedisWithExpire("monitor_"+v, "2", time.Hour*24)
|
||||||
|
offline += v + ","
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if offline != "" {
|
||||||
|
title := "设备状态异常"
|
||||||
|
content := "设备状态异常\n设备: " + offline + "\t时间:" + time.Now().String()
|
||||||
|
go SendMail(title, content)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendMail(title, content 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(title, content, []string{"3236990479@qq.com", "lijun@ljsea.top"})
|
||||||
|
if err != nil {
|
||||||
|
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"})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,496 @@
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"StuAcaWorksAI/dao"
|
||||||
|
"StuAcaWorksAI/proto"
|
||||||
|
"StuAcaWorksAI/service"
|
||||||
|
"StuAcaWorksAI/worker"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/golang-jwt/jwt"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetUpUserGroup(router *gin.Engine) {
|
||||||
|
userGroup := router.Group("/user")
|
||||||
|
userGroup.POST("/register", registerHandler)
|
||||||
|
userGroup.POST("/login", loginHandler)
|
||||||
|
userGroup.POST("/uuid", GetScanUUID)
|
||||||
|
userGroup.POST("/gqr", GetQRStatus)
|
||||||
|
userGroup.POST("/sqr", SetQRStatus)
|
||||||
|
userGroup.POST("/confirm", ConfirmQRLogin)
|
||||||
|
userGroup.POST("/search", SearchHandler)
|
||||||
|
userGroup.POST("/info", GetUserInfo)
|
||||||
|
userGroup.POST("/update", UpdateUserInfo)
|
||||||
|
userGroup.POST("/sync", GetSyncUserInfo)
|
||||||
|
userGroup.POST("/delete", DeleteUser)
|
||||||
|
userGroup.POST("/reset", ResetPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RLReq struct {
|
||||||
|
User string `json:"username" form:"username"`
|
||||||
|
Email string `json:"email" form:"email"`
|
||||||
|
Password string `json:"password" form:"password"`
|
||||||
|
Age int `json:"age" form:"age"`
|
||||||
|
Gender string `json:"gender" form:"gender"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type QRReq struct {
|
||||||
|
UUID string `json:"uuid" form:"uuid"`
|
||||||
|
Address string `json:"address" form:"address"`
|
||||||
|
IP string `json:"ip" form:"ip"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SearchReq struct {
|
||||||
|
Keyword string `json:"keyword" form:"keyword"`
|
||||||
|
ID int `json:"id" form:"id"`
|
||||||
|
}
|
||||||
|
type GetUserInfoReq struct {
|
||||||
|
ID int `json:"id" form:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
//随机字符串验证码大写
|
||||||
|
code := worker.GetRandomString(6)
|
||||||
|
worker.SetRedisWithExpire("reset_password_"+req_data.Email, code, time.Minute*5) //设置5分钟过期`
|
||||||
|
//发送邮件
|
||||||
|
service.SendEmail(req_data.Email, "大学生学业作品AI生成工具开发重置密码", "验证码:"+code+" ,请在5分钟内使用!")
|
||||||
|
} 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)
|
||||||
|
} 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)
|
||||||
|
} 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
|
||||||
|
}
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "2"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUserInfo(c *gin.Context) {
|
||||||
|
var req_data GetUserInfoReq
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
user_id := int(id.(float64))
|
||||||
|
if err := c.ShouldBind(&req_data); err == nil {
|
||||||
|
var user dao.User
|
||||||
|
if req_data.ID == user_id {
|
||||||
|
user = dao.FindUserByID2(user_id)
|
||||||
|
user.Password = "" //不返回密码
|
||||||
|
} else {
|
||||||
|
//判断当前用户是否有权限查看
|
||||||
|
cur_user := dao.FindUserByID2(user_id)
|
||||||
|
if cur_user.Role == "admin" {
|
||||||
|
user = dao.FindUserByID2(req_data.ID)
|
||||||
|
user.Password = "" //不返回密码
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.PermissionDenied, "message": "无权查看", "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": user})
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.ParameterError, "message": err, "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
var req_data proto.UpdateUserInfoReq
|
||||||
|
id, _ := c.Get("id")
|
||||||
|
user_id := int(id.(float64))
|
||||||
|
if err := c.ShouldBind(&req_data); err == nil {
|
||||||
|
rid, err2 := service.UpdateUser(user_id, req_data)
|
||||||
|
if err2 != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.OperationFailed, "message": "failed", "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": rid})
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.ParameterError, "message": err, "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetScanUUID(c *gin.Context) {
|
||||||
|
var ReqData QRReq
|
||||||
|
if err := c.ShouldBind(&ReqData); err != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err, "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := map[string]interface{}{"status": "0", "address": ReqData.Address, "ip": c.ClientIP()}
|
||||||
|
jsonData, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err, "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
res := worker.SetRedisWithExpire(id.String(), string(jsonData), time.Minute*30)
|
||||||
|
if res {
|
||||||
|
var retrievedData map[string]interface{}
|
||||||
|
if err2 := json.Unmarshal([]byte(worker.GetRedis(id.String())), &retrievedData); err2 != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err2, "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": retrievedData, "data": id.String()})
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.RedisSetError, "message": "qr code invalid", "data": "1"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetQRStatus(c *gin.Context) {
|
||||||
|
var qrsetReq QRReq
|
||||||
|
if err := c.ShouldBind(&qrsetReq); err == nil && qrsetReq.UUID != "" {
|
||||||
|
if worker.IsContainKey(qrsetReq.UUID) == false {
|
||||||
|
c.JSON(200, gin.H{"code": proto.UUIDNotFound, "message": "uuid not found in server", "data": "0"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var retrievedData map[string]interface{}
|
||||||
|
if err2 := json.Unmarshal([]byte(worker.GetRedis(qrsetReq.UUID)), &retrievedData); err2 != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err2, "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
retrievedData["status"] = "1"
|
||||||
|
jsonData, err2 := json.Marshal(retrievedData)
|
||||||
|
if err2 != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err2, "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := worker.SetRedisWithExpire(qrsetReq.UUID, string(jsonData), time.Minute*30)
|
||||||
|
if res {
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": retrievedData})
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.RedisSetError, "message": "qr code invalid", "data": "1"})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err, "data": "2"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认返回token数据
|
||||||
|
func ConfirmQRLogin(c *gin.Context) {
|
||||||
|
var qrsetReq QRReq
|
||||||
|
if err := c.ShouldBind(&qrsetReq); err == nil && qrsetReq.UUID != "" {
|
||||||
|
//user_id, _ := c.Get("id")
|
||||||
|
user_name, _ := c.Get("username")
|
||||||
|
if user_name != "" {
|
||||||
|
key := "user_" + user_name.(string)
|
||||||
|
token := worker.GetRedis(key)
|
||||||
|
if token == "" {
|
||||||
|
c.JSON(200, gin.H{"code": proto.RedisGetError, "message": "Token不存在", "data": "20"})
|
||||||
|
}
|
||||||
|
if worker.IsContainKey(qrsetReq.UUID) == false {
|
||||||
|
c.JSON(200, gin.H{"code": proto.UUIDNotFound, "message": "uuid not found in server", "data": "0"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var retrievedData map[string]interface{}
|
||||||
|
if err2 := json.Unmarshal([]byte(worker.GetRedis(qrsetReq.UUID)), &retrievedData); err2 != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err2, "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
retrievedData["status"] = token
|
||||||
|
jsonData, err2 := json.Marshal(retrievedData)
|
||||||
|
if err2 != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err2, "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if worker.SetRedisWithExpire(qrsetReq.UUID, string(jsonData), time.Minute*10) {
|
||||||
|
c.JSON(200, gin.H{"code": 0, "message": "success", "data": "0"})
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.RedisSetError, "message": "设置Token失败", "data": "8"})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.RedisGetError, "message": "failed", "data": "20"})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err, "data": "3"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetQRStatus(c *gin.Context) {
|
||||||
|
var qrReq QRReq
|
||||||
|
if err := c.ShouldBind(&qrReq); err == nil {
|
||||||
|
var retrievedData map[string]interface{}
|
||||||
|
if err2 := json.Unmarshal([]byte(worker.GetRedis(qrReq.UUID)), &retrievedData); err2 != nil {
|
||||||
|
c.JSON(200, gin.H{"code": proto.DeviceRestartFailed, "message": err2, "data": "2"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
str := retrievedData["status"].(string)
|
||||||
|
switch str {
|
||||||
|
case "":
|
||||||
|
c.JSON(200, gin.H{"code": proto.UUIDNotFound, "message": "uuid not found", "data": "0"}) //空值
|
||||||
|
case "0":
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "0"}) //空值
|
||||||
|
case "1":
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": "1"}) //已扫描待确认
|
||||||
|
default:
|
||||||
|
// 解析 JWT 令牌
|
||||||
|
token, err := jwt.Parse(str, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
return proto.SigningKey, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, gin.H{"error": err.Error(), "code": proto.TokenParseError, "message": "error"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 返回令牌
|
||||||
|
data := make(map[string]interface{})
|
||||||
|
data["id"] = token.Claims.(jwt.MapClaims)["id"]
|
||||||
|
data["username"] = token.Claims.(jwt.MapClaims)["username"]
|
||||||
|
data["email"] = token.Claims.(jwt.MapClaims)["email"]
|
||||||
|
data["token"] = str
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": data}) //确认返回token数据
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"error": err.Error(), "code": proto.DeviceRestartFailed, "message": "error"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SearchHandler(c *gin.Context) {
|
||||||
|
var req_data SearchReq
|
||||||
|
if err := c.ShouldBind(&req_data); err == nil {
|
||||||
|
if req_data.ID != -1 {
|
||||||
|
user := service.GetUserByID(req_data.ID)
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": user})
|
||||||
|
return
|
||||||
|
} else if req_data.Keyword != "" {
|
||||||
|
users := service.GetUserByNameLike(req_data.Keyword)
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": users})
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"code": proto.ParameterError, "message": "error", "data": "无ID 与 关键字"})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "error"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loginHandler(c *gin.Context) {
|
||||||
|
var req_data RLReq
|
||||||
|
tokenString := ""
|
||||||
|
if err := c.ShouldBind(&req_data); err == nil {
|
||||||
|
if len(req_data.Password) != 32 {
|
||||||
|
hasher := md5.New()
|
||||||
|
hasher.Write([]byte(req_data.Password)) // 生成密码的 MD5 散列值
|
||||||
|
req_data.Password = hex.EncodeToString(hasher.Sum(nil)) // 生成密码的 MD5 散列值
|
||||||
|
}
|
||||||
|
user := service.GetUser(req_data.User, req_data.Password, req_data.Password)
|
||||||
|
if user.ID != 0 {
|
||||||
|
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 {
|
||||||
|
c.JSON(200, gin.H{"error": err.Error(), "code": proto.TokenGenerationError, "message": "error"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
// 返回令牌
|
||||||
|
data := make(map[string]interface{})
|
||||||
|
data["id"] = user.ID
|
||||||
|
data["username"] = user.Name
|
||||||
|
data["email"] = user.Email
|
||||||
|
data["token"] = tokenString
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": data})
|
||||||
|
} else {
|
||||||
|
//用户名或密码错误
|
||||||
|
c.JSON(200, gin.H{"error": "用户名或密码错误", "code": proto.UsernameOrPasswordError, "message": "error"})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"error": err.Error(), "code": proto.DeviceRestartFailed, "message": "error"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerHandler(c *gin.Context) {
|
||||||
|
var req_data RLReq
|
||||||
|
tokenString := ""
|
||||||
|
var id uint
|
||||||
|
if err := c.ShouldBind(&req_data); err == nil {
|
||||||
|
if len(req_data.Password) != 32 {
|
||||||
|
hasher := md5.New()
|
||||||
|
hasher.Write([]byte(req_data.Password)) // 生成密码的 MD5 散列值
|
||||||
|
req_data.Password = hex.EncodeToString(hasher.Sum(nil)) // 生成密码的 MD5 散列值
|
||||||
|
}
|
||||||
|
if service.ContainsUser(req_data.User, req_data.Email) == true {
|
||||||
|
c.JSON(200, gin.H{"error": "user already exists", "code": proto.UsernameExists, "message": "error"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id = service.CreateUser(req_data.User, req_data.Password, req_data.Email, req_data.Gender, req_data.Age)
|
||||||
|
if id == 0 {
|
||||||
|
c.JSON(200, gin.H{"error": "create user error", "code": proto.OperationFailed, "message": "error"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 生成 JWT 令牌
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||||
|
"username": req_data.User,
|
||||||
|
"id": id,
|
||||||
|
"exp": time.Now().Add(time.Hour * 10).Unix(), // 令牌过期时间, 1分钟后过期
|
||||||
|
})
|
||||||
|
tokenString, err = token.SignedString(proto.SigningKey)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, gin.H{"error": err.Error(), "code": proto.TokenGenerationError, "message": "error"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.JSON(200, gin.H{"error": err.Error(), "code": proto.ParameterError, "message": "error"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(req_data)
|
||||||
|
res := worker.SetRedisWithExpire(tokenString, tokenString, time.Hour*10) // 设置过期时间为10分钟
|
||||||
|
if !res {
|
||||||
|
c.JSON(200, gin.H{"error": "set token error", "code": proto.RedisSetError, "message": "error"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 返回令牌
|
||||||
|
data := make(map[string]interface{})
|
||||||
|
data["id"] = id
|
||||||
|
data["username"] = req_data.User
|
||||||
|
data["email"] = req_data.Email
|
||||||
|
data["token"] = tokenString
|
||||||
|
c.JSON(200, gin.H{"code": proto.SuccessCode, "message": "success", "data": data})
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,363 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"StuAcaWorksAI/dao"
|
||||||
|
"StuAcaWorksAI/handler"
|
||||||
|
"StuAcaWorksAI/proto"
|
||||||
|
"StuAcaWorksAI/service"
|
||||||
|
"StuAcaWorksAI/worker"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/golang-jwt/jwt"
|
||||||
|
"github.com/robfig/cron/v3"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
gin.SetMode(gin.ReleaseMode)
|
||||||
|
r := gin.Default()
|
||||||
|
err := dao.Init()
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to connect database:" + err.Error())
|
||||||
|
}
|
||||||
|
err = worker.InitRedis()
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to connect redis:" + err.Error())
|
||||||
|
}
|
||||||
|
r.Use(handler.CrosHandler())
|
||||||
|
r.Use(JWTAuthMiddleware()) // 使用 JWT 认证中间件
|
||||||
|
handler.SetUpUserGroup(r) // User
|
||||||
|
handler.SetUpToolGroup(r) // Tool
|
||||||
|
handler.SetUpFileGroup(r) // File
|
||||||
|
defer dao.Close()
|
||||||
|
defer worker.CloseRedis()
|
||||||
|
//定时任务
|
||||||
|
c := cron.New(cron.WithSeconds())
|
||||||
|
// 添加每 10 秒执行一次的任务
|
||||||
|
_, err = c.AddFunc("@every 10s", myTask)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("添加定时任务失败: ", err)
|
||||||
|
}
|
||||||
|
c.Start()
|
||||||
|
//读取配置文件,设置系统
|
||||||
|
ReadConfigToSetSystem()
|
||||||
|
r.Run(":" + proto.Config.SERVER_PORT) // listen and serve on 0.0.0.0:8083
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
// 创建cid的目录
|
||||||
|
os.MkdirAll(proto.CID_BASE_DIR, os.ModePerm)
|
||||||
|
os.MkdirAll(proto.CID_BASE_DIR+"script", os.ModePerm)
|
||||||
|
os.MkdirAll(proto.CID_BASE_DIR+"workspace", os.ModePerm)
|
||||||
|
//读取配置文件
|
||||||
|
//文件地址/home/saw-ai/saw-ai.conf
|
||||||
|
configPath := "/home/saw-ai/saw-ai.conf"
|
||||||
|
//读取配置文件
|
||||||
|
err := proto.ReadConfig(configPath)
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to read config file:" + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeLogger(c *gin.Context) {
|
||||||
|
ip := c.ClientIP()
|
||||||
|
method := c.Request.Method
|
||||||
|
path := c.Request.URL.Path
|
||||||
|
params := ""
|
||||||
|
|
||||||
|
if method == "GET" {
|
||||||
|
params = c.Request.URL.RawQuery
|
||||||
|
}
|
||||||
|
if method == "POST" && !strings.Contains(c.Request.URL.Path, "/upload") {
|
||||||
|
params = c.Request.PostForm.Encode()
|
||||||
|
if params == "" {
|
||||||
|
// 请求体
|
||||||
|
bodyBytes, _ := io.ReadAll(c.Request.Body)
|
||||||
|
c.Request.Body = io.NopCloser(strings.NewReader(string(bodyBytes))) // Write body back, so other handler can read it too
|
||||||
|
params = string(bodyBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.Contains(c.Request.URL.Path, "/upload") {
|
||||||
|
params = "upload file"
|
||||||
|
}
|
||||||
|
go dao.InsertLogToDB(path, ip, method, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func JWTAuthMiddleware() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
if proto.Config.LOG_SAVE_DAYS > 0 {
|
||||||
|
writeLogger(c)
|
||||||
|
}
|
||||||
|
// 从请求头中获取 JWT 令牌
|
||||||
|
tokenString := c.Request.Header.Get("token")
|
||||||
|
|
||||||
|
//请求方式为get时,从url中获取token
|
||||||
|
if tokenString == "" {
|
||||||
|
tokenString = c.Query("token")
|
||||||
|
}
|
||||||
|
//如果请求为login或register,则不需要验证token
|
||||||
|
for k, _ := range proto.Url_map {
|
||||||
|
if strings.Contains(c.Request.URL.Path, k) {
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tokenString == "" {
|
||||||
|
//c.AbortWithStatus(200)
|
||||||
|
c.JSON(200, gin.H{
|
||||||
|
"message": "Unauthorized",
|
||||||
|
"error": "token is empty",
|
||||||
|
"code": proto.TokenIsNull,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if proto.Config.TOKEN_USE_REDIS {
|
||||||
|
redisToken := worker.GetRedis(tokenString)
|
||||||
|
if redisToken == "" {
|
||||||
|
c.AbortWithStatus(200)
|
||||||
|
c.JSON(200, gin.H{
|
||||||
|
"message": "NOT_LOGIN",
|
||||||
|
"error": "server token is empty",
|
||||||
|
"code": proto.TokenIsNull,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//查看token是否在超级token中
|
||||||
|
if worker.IsContainSet("super_permission_tokens", tokenString) {
|
||||||
|
sId := c.Request.Header.Get("super_id")
|
||||||
|
if sId == "" {
|
||||||
|
sId = c.Query("super_id")
|
||||||
|
}
|
||||||
|
if sId == "" {
|
||||||
|
c.AbortWithStatus(200)
|
||||||
|
c.JSON(200, gin.H{
|
||||||
|
"message": "NOT_LOGIN",
|
||||||
|
"error": "super_id is empty",
|
||||||
|
"code": proto.TokenIsNull,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id, _ := strconv.Atoi(sId)
|
||||||
|
idFloat64 := float64(id)
|
||||||
|
//查看s_id类型
|
||||||
|
c.Set("id", idFloat64)
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用加密secret 解析 JWT 令牌
|
||||||
|
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
return proto.SigningKey, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
// 验证令牌
|
||||||
|
if err != nil || !token.Valid {
|
||||||
|
c.AbortWithStatus(200)
|
||||||
|
c.JSON(200, gin.H{
|
||||||
|
"message": "NOT_LOGIN",
|
||||||
|
"error": "Invalid token",
|
||||||
|
"code": proto.TokenExpired,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将用户信息添加到上下文中
|
||||||
|
c.Set("id", token.Claims.(jwt.MapClaims)["id"])
|
||||||
|
c.Set("username", token.Claims.(jwt.MapClaims)["username"])
|
||||||
|
|
||||||
|
if UserFuncIntercept(int(token.Claims.(jwt.MapClaims)["id"].(float64)), c.Request.URL.Path) {
|
||||||
|
c.AbortWithStatus(200)
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"message": "no function permission",
|
||||||
|
"error": "no permission",
|
||||||
|
"code": proto.NoPermission,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 继续处理请求
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func myTask() {
|
||||||
|
// 定时任务
|
||||||
|
//redis中取出数据
|
||||||
|
//handler.RunCron()
|
||||||
|
if proto.Config.MONITOR {
|
||||||
|
handler.ScanDeviceStatus()
|
||||||
|
}
|
||||||
|
//其它定时任务-通用
|
||||||
|
RunGeneralCron()
|
||||||
|
}
|
||||||
|
|
||||||
|
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添加通用定时任务
|
||||||
|
key := "cron_info"
|
||||||
|
//日志清理
|
||||||
|
res := worker.GetRedis(key)
|
||||||
|
var cron_infos []proto.CronInfo
|
||||||
|
if res != "" {
|
||||||
|
err := json.Unmarshal([]byte(res), &cron_infos)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("ReadConfigToSetSystem Error decoding config,key value is :", res)
|
||||||
|
}
|
||||||
|
|
||||||
|
//查看清除日志任务是否存在
|
||||||
|
if proto.Config.LOG_SAVE_DAYS > 0 {
|
||||||
|
var is_exist bool
|
||||||
|
for _, v := range cron_infos {
|
||||||
|
if v.Type == 1 {
|
||||||
|
is_exist = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !is_exist {
|
||||||
|
var logClean proto.CronInfo
|
||||||
|
logClean.Type = 1
|
||||||
|
logClean.Info = "日志清理"
|
||||||
|
logClean.Curr = 86400
|
||||||
|
logClean.Every = 86400
|
||||||
|
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 {
|
||||||
|
if proto.Config.LOG_SAVE_DAYS > 0 {
|
||||||
|
var logClean proto.CronInfo
|
||||||
|
logClean.Type = 1
|
||||||
|
logClean.Info = "日志清理"
|
||||||
|
logClean.Curr = 86400
|
||||||
|
logClean.Every = 86400
|
||||||
|
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
|
||||||
|
json_data, err := json.Marshal(cron_infos)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("ReadConfigToSetSystem Error encoding config,value is :", cron_infos)
|
||||||
|
} else {
|
||||||
|
worker.SetRedis(key, string(json_data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunGeneralCron() {
|
||||||
|
//redis添加通用定时任务
|
||||||
|
key := "cron_info"
|
||||||
|
//日志清理
|
||||||
|
res := worker.GetRedis(key)
|
||||||
|
var cron_infos []proto.CronInfo
|
||||||
|
if res != "" {
|
||||||
|
err := json.Unmarshal([]byte(res), &cron_infos)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("RunGeneralCron Error decoding config,key value is :", res)
|
||||||
|
}
|
||||||
|
for i, v := range cron_infos {
|
||||||
|
//1:日志清理,其他待定
|
||||||
|
if v.Type == 1 {
|
||||||
|
//日志清理
|
||||||
|
if v.Curr <= 0 {
|
||||||
|
//执行日志清理
|
||||||
|
go dao.DeleteLog(proto.Config.LOG_SAVE_DAYS)
|
||||||
|
v.Curr = v.Every
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
json_data, err := json.Marshal(cron_infos)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("RunGeneralCron Error encoding config,value is :", cron_infos)
|
||||||
|
} else {
|
||||||
|
worker.SetRedis(key, string(json_data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户功能拦截,返回true表示拦截,false表示不拦截
|
||||||
|
func UserFuncIntercept(id int, url string) bool {
|
||||||
|
//先查看是否有权限
|
||||||
|
user := dao.FindUserByUserID(id)
|
||||||
|
//如果用户有权限,则不拦截
|
||||||
|
for k, v := range proto.Per_menu_map {
|
||||||
|
if strings.Contains(url, k) {
|
||||||
|
if v == 1 && user.VideoFunc == false {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if v == 2 && user.DeviceFunc == false {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if v == 3 && user.CIDFunc == false {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Config ConfigStruct
|
||||||
|
var SigningKey = []byte{}
|
||||||
|
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} // 不需要token验证的url
|
||||||
|
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} // 文件类型
|
||||||
|
const (
|
||||||
|
MYSQL_USER = "video_t2"
|
||||||
|
MYSQL_DB = "video_t2"
|
||||||
|
MYSQL_PASSWORD = "2t2SKHmWEYj2xFKF"
|
||||||
|
MYSQL_PORT = "3306"
|
||||||
|
MYSQL_HOST = "127.0.0.1"
|
||||||
|
MYSQL_DSN = MYSQL_USER + ":" + MYSQL_PASSWORD + "@tcp(" + MYSQL_HOST + ":" + MYSQL_PORT + ")/" + MYSQL_DB + "?charset=utf8mb4&parseTime=True&loc=Local"
|
||||||
|
|
||||||
|
REDIS_ADDR = "127.0.0.1:6379"
|
||||||
|
REDIS_PASSWORD = "lj502138"
|
||||||
|
REIDS_DB = 2
|
||||||
|
|
||||||
|
TOKEN_SECRET = "mfjurnc_32ndj9dfhj"
|
||||||
|
|
||||||
|
// 以下是持续集成、部署的配置
|
||||||
|
CID_BASE_DIR = "/home/lijun/cid/"
|
||||||
|
|
||||||
|
// 以下是文件上传的配置
|
||||||
|
FILE_BASE_DIR = "/home/lijun/file/"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// 以下是消息类型
|
||||||
|
MSG_TYPE_SIMPLE = 1 // 单聊
|
||||||
|
MSG_TYPE_GROUP = 2 // 群聊
|
||||||
|
MSG_TYPE_SYSTEM = 3 // 系统消息
|
||||||
|
MSG_TYPE_FRIEND = 4 // 好友请求
|
||||||
|
MSG_TYPE_GROUP_ADD = 5 // 加入群聊请求
|
||||||
|
MSG_TYPE_GROUP_INVI = 6 // 邀请加入群聊
|
||||||
|
|
||||||
|
// 以下是消息状态
|
||||||
|
MSG_STATUS_READ = 1 // 已读
|
||||||
|
MSG_STATUS_UNREAD = 0 // 未读
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
//文件上传类型
|
||||||
|
File_TYPE = 1 // 通用文件
|
||||||
|
//用于视频解析
|
||||||
|
Video_TYPE = 2 // 视频文件
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
gorm.Model
|
||||||
|
Name string `gorm:"column:name"`
|
||||||
|
Age int `gorm:"column:age"`
|
||||||
|
Email string `gorm:"column:email"`
|
||||||
|
Gender string `gorm:"column:gender"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigStruct struct {
|
||||||
|
DB int `json:"db"` // 0: mysql, 1: pg
|
||||||
|
MYSQL_DSN string `json:"mysql_dsn"`
|
||||||
|
PG_DSN string `json:"pg_dsn"`
|
||||||
|
REDIS_ADDR string `json:"redis_addr"`
|
||||||
|
TOKEN_USE_REDIS bool `json:"token_use_redis"`
|
||||||
|
REDIS_User_PW bool `json:"redis_user_pw"` // 是否使用密码
|
||||||
|
REDIS_PASSWORD string `json:"redis_password"`
|
||||||
|
REDIS_DB int `json:"redis_db"`
|
||||||
|
TOKEN_SECRET string `json:"token_secret"`
|
||||||
|
CID_BASE_DIR string `json:"cid_base_dir"`
|
||||||
|
FILE_BASE_DIR string `json:"file_base_dir"`
|
||||||
|
MONITOR bool `json:"monitor"` // 状态监控及邮件通知
|
||||||
|
SERVER_SQL_LOG bool `json:"server_sql_log"` // 服务器sql日志
|
||||||
|
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"` // 服务器名称,用于区分不同服务器
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取配置文件
|
||||||
|
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文件
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error opening config file")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
decoder := json.NewDecoder(file)
|
||||||
|
err = decoder.Decode(&Config)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error decoding config")
|
||||||
|
} else {
|
||||||
|
if Config.SERVER_PORT == "" {
|
||||||
|
Config.SERVER_PORT = "8083" // 默认端口
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SigningKey = []byte(Config.TOKEN_SECRET)
|
||||||
|
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,76 @@
|
||||||
|
package proto
|
||||||
|
|
||||||
|
const (
|
||||||
|
SuccessCode = 0 // 成功
|
||||||
|
|
||||||
|
// 通用错误码
|
||||||
|
ErrorCode = 1 // 未知错误或服务器内部错误
|
||||||
|
ParameterError = 9 // 请求参数解析错误
|
||||||
|
OperationFailed = 17 // 数据库数据操作失败
|
||||||
|
DataNotFound = 14 // 查询数据失败
|
||||||
|
InternalServerError = 10 // 服务器内部错误
|
||||||
|
|
||||||
|
// Token相关错误码
|
||||||
|
TokenInvalid = 2 // Token失效,未登录
|
||||||
|
TokenIsNull = 3 // Token为空
|
||||||
|
TokenExpired = 4 // Token已过期
|
||||||
|
TokenGenerationError = 5 // Token生成错误
|
||||||
|
TokenParseError = 19 // Token解析错误
|
||||||
|
|
||||||
|
// 用户名密码相关错误码
|
||||||
|
UsernameOrPasswordError = 6 // 用户名或密码错误
|
||||||
|
UsernameExists = 7 // 用户名已存在
|
||||||
|
PermissionDenied = 21 // 权限不足
|
||||||
|
|
||||||
|
// Redis相关错误码
|
||||||
|
RedisSetError = 8 // 设置redis错误
|
||||||
|
RedisGetError = 20 // 获取redis错误
|
||||||
|
|
||||||
|
// 视频操作相关错误码
|
||||||
|
VideoDelayOperationFailed = 11 // 视频延迟操作失败
|
||||||
|
VideoDeleteFailed = 12 // 视频删除失败
|
||||||
|
|
||||||
|
// 设备操作相关错误码
|
||||||
|
DeviceRestartFailed = 13 // 设备重启失败
|
||||||
|
DeviceAddFailed = 15 // 设备添加失败
|
||||||
|
DeviceUpdateFailed = 16 // 设备修改失败
|
||||||
|
|
||||||
|
// 撤销操作相关错误码
|
||||||
|
RevokeOperation = 30 // 撤销
|
||||||
|
RevokeDelayOperationFailed = 31 // 撤销延迟操作失败
|
||||||
|
RevokeOperationFailed = 32 // 撤销操作失败
|
||||||
|
|
||||||
|
// UUID相关错误码
|
||||||
|
UUIDNotFound = 18 // uuid不存在
|
||||||
|
|
||||||
|
//Tool
|
||||||
|
NoRedisPermissions = 51
|
||||||
|
NoRunPermissions = 52
|
||||||
|
NoDevicePermissions = 53
|
||||||
|
NoPermission = 54
|
||||||
|
|
||||||
|
//消息错误码
|
||||||
|
MsgSendFailed = 61 // 消息发送失败
|
||||||
|
|
||||||
|
//文件错误码
|
||||||
|
FileNotFound = 71 // 文件不存在
|
||||||
|
FileUploadFailed = 72 // 文件上传失败
|
||||||
|
SaveFileInfoFailed = 73 // 保存文件信息失败
|
||||||
|
SaveFileFailed = 74 // 保存文件失败
|
||||||
|
UploadFileFailed = 75 // 上传文件失败
|
||||||
|
NoUploadPermissions = 76 // 无上传权限
|
||||||
|
DeleteFileFailed = 77 // 删除文件失败
|
||||||
|
DeleteFileInfoFailed = 78 // 删除文件信息失败
|
||||||
|
|
||||||
|
DataFormatError = 80 // 数据格式错误
|
||||||
|
|
||||||
|
AddConfigFileFailed = 90 // 添加配置文件失败
|
||||||
|
UpdateConfigFailed = 91 // 更新配置失败
|
||||||
|
DeleteConfigFailed = 92 // 删除配置失败
|
||||||
|
SearchConfigFileFailed = 93 // 获取配置失败
|
||||||
|
|
||||||
|
ShellCreateFailed = 100 // 创建shell失败
|
||||||
|
ShellUpdateFailed = 101 // 更新shell失败
|
||||||
|
ShellDeleteFailed = 102 // 删除shell失败
|
||||||
|
ShellSearchFailed = 103 // 获取shell失败
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateUserInfoReq struct {
|
||||||
|
ID int `json:"id" form:"id"` //用户id
|
||||||
|
Username string `json:"name" form:"name"` //用户名
|
||||||
|
Age int `json:"age" form:"age"` //年龄
|
||||||
|
Role string `json:"role" form:"role"` //角色
|
||||||
|
Gender string `json:"gender" form:"gender"` //性别
|
||||||
|
Redis bool `json:"redis" form:"redis"` //是否刷新redis
|
||||||
|
Upload bool `json:"upload" form:"upload"` //是否上传头像
|
||||||
|
VideoFunc bool `json:"video_func" form:"video_func"` //视频功能
|
||||||
|
DeviceFunc bool `json:"device_func" form:"device_func"` //设备功能
|
||||||
|
CIDFunc bool `json:"cid_func" form:"cid_func"` //持续集成功能
|
||||||
|
Run bool `json:"run" form:"run"` //是否运行
|
||||||
|
Avatar string `json:"avatar" form:"avatar"` //头像
|
||||||
|
}
|
||||||
|
|
||||||
|
type CIDRUN struct {
|
||||||
|
CID uint `json:"cid" form:"cid"` //持续集成ID,查找持续集成任务
|
||||||
|
Curr int `json:"curr" form:"curr"` //当前剩余时间,每次执行减10s小于等于0则执行
|
||||||
|
Every int `json:"every" form:"every"` //每隔多少秒执行一次,小于等于0表示不执行,时间粒度为10s
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用于执行函数,方法
|
||||||
|
type CronInfo struct {
|
||||||
|
Type int `json:"type" form:"type"` //类型编码,1日志清理(且只会有一个),其他待定,2从服务器同步数据
|
||||||
|
Info string `json:"info" form:"info"` //信息
|
||||||
|
Curr int `json:"curr" form:"curr"` //当前剩余时间,每次执行减10s小于等于0则执行
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"db":0,
|
||||||
|
"mysql_dsn":"video_t2:2t2SKHmWEYj2xFKF@tcp(127.0.0.1:3306)/video_t2?charset=utf8mb4&parseTime=True&loc=Local",
|
||||||
|
"pg_dsn":"host=localhost user=video_t2 dbname=video_t2 password=2t2SKHmWEYj2xFKF port=5432 TimeZone=Asia/Shanghai",
|
||||||
|
"redis_addr":"127.0.0.1:6379",
|
||||||
|
"redis_db":2,
|
||||||
|
"redis_user_pw":true,
|
||||||
|
"token_use_redis":true,
|
||||||
|
"redis_password":"lj502138",
|
||||||
|
"token_secret":"mfjurnc_32ndj9dfhj",
|
||||||
|
"file_base_dir":"/home/lijun/file/",
|
||||||
|
"monitor":false,
|
||||||
|
"server_port":"8083"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,219 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"StuAcaWorksAI/dao"
|
||||||
|
"StuAcaWorksAI/proto"
|
||||||
|
"StuAcaWorksAI/worker"
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 检查path是否存在当前日期文件夹如(2024-08-09),不存在则path下当前日期文件夹创建,存在则返回
|
||||||
|
func getFilePath(path string) string {
|
||||||
|
//当前日期,格式为2024-08-09
|
||||||
|
date := time.Now().Format("2006-01-02")
|
||||||
|
//拼接文件路径
|
||||||
|
filePath := path + "/" + date
|
||||||
|
//判断文件夹是否存在
|
||||||
|
_, err := os.Stat(filePath)
|
||||||
|
if err != nil {
|
||||||
|
//不存在则创建
|
||||||
|
os.MkdirAll(filePath, os.ModePerm)
|
||||||
|
}
|
||||||
|
return filePath
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveFile(c *gin.Context, file *multipart.FileHeader, uploadType string) (string, string, error) {
|
||||||
|
//获取文件后缀
|
||||||
|
fileSuffix := path.Ext(file.Filename)
|
||||||
|
//生成文件名
|
||||||
|
fileStoreName := uuid.NewString() + fileSuffix
|
||||||
|
//生成文件路径
|
||||||
|
path_ := getFilePath(proto.FILE_BASE_DIR)
|
||||||
|
filePath := path_ + "/" + fileStoreName
|
||||||
|
//保存文件
|
||||||
|
if err := c.SaveUploadedFile(file, filePath); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
if uploadType == "2" {
|
||||||
|
worker.PushRedisList("video_need_handle", filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
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,7 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import "StuAcaWorksAI/dao"
|
||||||
|
|
||||||
|
func insertLog(url, ip, method, params string) uint {
|
||||||
|
return dao.InsertLogToDB(url, ip, method, params)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"StuAcaWorksAI/proto"
|
||||||
|
"StuAcaWorksAI/worker"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetToolRedisList(key string, value string, expire int) (code int, message string) {
|
||||||
|
if expire == 0 {
|
||||||
|
if worker.PushRedisList(key, value) {
|
||||||
|
return proto.SuccessCode, "success"
|
||||||
|
} else {
|
||||||
|
return proto.OperationFailed, "push redis list failed"
|
||||||
|
}
|
||||||
|
} else if expire > 0 {
|
||||||
|
if worker.PushRedisListWithExpire(key, value, time.Duration(expire)) {
|
||||||
|
return proto.SuccessCode, "success"
|
||||||
|
} else {
|
||||||
|
return proto.OperationFailed, "push redis list with expire failed"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return proto.ParameterError, "expire time can not be negative"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetToolRedisSet(key string, value string, expire int) (code int, message string) {
|
||||||
|
if expire == 0 {
|
||||||
|
if worker.SetRedis(key, value) {
|
||||||
|
return proto.SuccessCode, "success"
|
||||||
|
} else {
|
||||||
|
return proto.OperationFailed, "set redis failed"
|
||||||
|
}
|
||||||
|
} else if expire > 0 {
|
||||||
|
if worker.SetRedisWithExpire(key, value, time.Duration(expire)) {
|
||||||
|
return proto.SuccessCode, "success"
|
||||||
|
} else {
|
||||||
|
return proto.OperationFailed, "set redis with expire failed"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return proto.ParameterError, "expire time can not be negative"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetToolRedisKV(key string, value string, expire int) (code int, message string) {
|
||||||
|
if expire == 0 {
|
||||||
|
if worker.SetRedis(key, value) {
|
||||||
|
return proto.SuccessCode, "success"
|
||||||
|
} else {
|
||||||
|
return proto.OperationFailed, "set redis failed"
|
||||||
|
}
|
||||||
|
} else if expire > 0 {
|
||||||
|
if worker.SetRedisWithExpire(key, value, time.Duration(expire)) {
|
||||||
|
return proto.SuccessCode, "success"
|
||||||
|
} else {
|
||||||
|
return proto.OperationFailed, "set redis with expire failed"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return proto.ParameterError, "expire time can not be negative"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetToolRedis(key string) (code int, message string) {
|
||||||
|
val := worker.GetRedis(key)
|
||||||
|
if val == "" {
|
||||||
|
return proto.OperationFailed, "get redis failed"
|
||||||
|
} else {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,369 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"StuAcaWorksAI/dao"
|
||||||
|
"StuAcaWorksAI/proto"
|
||||||
|
"StuAcaWorksAI/worker"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateUser(name, password, email, gender string, age int) uint {
|
||||||
|
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 {
|
||||||
|
emailRegex := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`
|
||||||
|
re := regexp.MustCompile(emailRegex)
|
||||||
|
var user dao.User
|
||||||
|
if re.MatchString(name) {
|
||||||
|
user = dao.FindUserByEmail(name)
|
||||||
|
} else {
|
||||||
|
user = dao.FindUserByName(name)
|
||||||
|
}
|
||||||
|
if user.ID != 0 && user.Password == password {
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
return dao.User{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContainsUser(name, email string) bool {
|
||||||
|
user := dao.FindUserByName(name)
|
||||||
|
user2 := dao.FindUserByEmail(email)
|
||||||
|
if user.ID != 0 || user2.ID != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUserByID(id int) []proto.User {
|
||||||
|
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 {
|
||||||
|
return dao.FindUserByNameLike(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateUser(user_id int, req proto.UpdateUserInfoReq) (int, error) {
|
||||||
|
cur_user := dao.FindUserByID2(user_id)
|
||||||
|
//fmt.Println("cur_user:", cur_user, "req:", req)
|
||||||
|
if user_id == req.ID && cur_user.Role != "admin" {
|
||||||
|
err := dao.UpdateUserByID3(user_id, req) //用户修改自己的信息,不能修改权限信息
|
||||||
|
//添加修改用户信息到同步列表
|
||||||
|
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" {
|
||||||
|
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
|
||||||
|
} else {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateUserCache(id int) {
|
||||||
|
key := "user_info_" + strconv.Itoa(id)
|
||||||
|
if worker.IsContainKey(key) {
|
||||||
|
user := GetUserByID(id)
|
||||||
|
userJson, err := json.Marshal(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
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
package worker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/smtp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MyEmail struct {
|
||||||
|
SmtpPort int
|
||||||
|
ImapPort int
|
||||||
|
SmtpHost string
|
||||||
|
SmtpUserName string
|
||||||
|
SmtpPassword string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *MyEmail) Send(title, content string, toEmail []string) error {
|
||||||
|
//捕获异常
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
fmt.Errorf("MyEmail send mail error: %s", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 设置邮件头部
|
||||||
|
header := make(map[string]string)
|
||||||
|
header["From"] = e.SmtpUserName
|
||||||
|
header["To"] = toEmail[0]
|
||||||
|
|
||||||
|
header["Subject"] = title
|
||||||
|
|
||||||
|
// 组装邮件消息
|
||||||
|
message := ""
|
||||||
|
for k, v := range header {
|
||||||
|
message += fmt.Sprintf("%s: %s\r\n", k, v)
|
||||||
|
}
|
||||||
|
message += "\r\n" + content
|
||||||
|
// 发送邮件
|
||||||
|
err := smtp.SendMail(e.SmtpHost, smtp.PlainAuth("", e.SmtpUserName, e.SmtpPassword, "pop.qq.com"), e.SmtpUserName, toEmail, []byte(message))
|
||||||
|
if err != nil {
|
||||||
|
//log.Fatalf("smtp error: %s", err)
|
||||||
|
fmt.Errorf("send mail error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,544 @@
|
||||||
|
package worker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"StuAcaWorksAI/proto"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var RedisClient *redis.Client // Redis 客户端, 用于连接 Redis 服务器
|
||||||
|
func InitRedis() error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
if proto.Config.REDIS_User_PW == false {
|
||||||
|
// 连接redis
|
||||||
|
RedisClient = redis.NewClient(&redis.Options{
|
||||||
|
Addr: proto.Config.REDIS_ADDR, // Redis 服务器地址
|
||||||
|
DB: proto.Config.REDIS_DB, // 使用的数据库编号
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 连接redis
|
||||||
|
RedisClient = redis.NewClient(&redis.Options{
|
||||||
|
Addr: proto.Config.REDIS_ADDR, // Redis 服务器地址
|
||||||
|
Password: proto.Config.REDIS_PASSWORD, // 如果 Redis 设置了密码
|
||||||
|
DB: proto.Config.REDIS_DB, // 使用的数据库编号
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证 Redis 客户端是否可以正常工作
|
||||||
|
_, err := RedisClient.Ping(ctx).Result()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error connecting to Redis: %v", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func CloseRedis() {
|
||||||
|
// 关闭 Redis 客户端
|
||||||
|
if err := RedisClient.Close(); err != nil {
|
||||||
|
fmt.Println("Error closing Redis client: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsContainKey(key string) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
val, err := RedisClient.Exists(ctx, key).Result() // 检查键是否存在, 如果存在则返回 1, 否则返回 0
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error getting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if val == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置redis
|
||||||
|
func SetRedis(key string, value string) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
// 设置键值对, 0 表示不设置过期时间, 如果需要设置过期时间, 可以设置为 time.Second * 10 等
|
||||||
|
err := RedisClient.Set(ctx, key, value, time.Minute*30).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
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
|
||||||
|
func SetHashWithTime(key string, id int, name, email string, duration time.Duration) bool {
|
||||||
|
//捕获错误,如果错误返回
|
||||||
|
|
||||||
|
ctx := context.Background() // 创建一个上下文
|
||||||
|
fields := map[string]interface{}{
|
||||||
|
"id": strconv.Itoa(id),
|
||||||
|
"name": name,
|
||||||
|
"email": email,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置哈希表的字段值, 0 表示不设置过期时间, 如果需要设置过期时间, 可以设置为 time.Second * 10 等
|
||||||
|
err := RedisClient.HSet(ctx, key, fields).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
err = RedisClient.Expire(ctx, key, time.Hour*10).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置redis hash,设置过期时间
|
||||||
|
func SetHash(key string, data map[string]interface{}) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.HSet(ctx, key, data).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("%v :Error setting hash: %v", key, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
err = RedisClient.Expire(ctx, key, time.Minute*30).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("%v :Error setting expire: %v", key, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetHashWithField(key string, field string, value string) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.HSet(ctx, key, field, value).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetHash(key string, field string) string {
|
||||||
|
ctx := context.Background()
|
||||||
|
val, err := RedisClient.HGet(ctx, key, field).Result()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error getting hash: %v", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetHashAll(key string) map[string]string {
|
||||||
|
ctx := context.Background()
|
||||||
|
val, err := RedisClient.HGetAll(ctx, key).Result()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error getting hash: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置redis
|
||||||
|
func SetRedisWithExpire(key string, value string, expire time.Duration) bool { // 设置键值对, 0 表示不设置过期时间, 如果需要设置过期时间, 可以设置为 time.Second * 10 等
|
||||||
|
ctx := context.Background()
|
||||||
|
// 设置键值对, 0 表示不设置过期时间, 如果需要设置过期时间, 可以设置为 time.Second * 10 等
|
||||||
|
err := RedisClient.Set(ctx, key, value, expire).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取redis
|
||||||
|
func GetRedis(key string) string {
|
||||||
|
ctx := context.Background()
|
||||||
|
val, err := RedisClient.Get(ctx, key).Result() // 从 Redis 读取键值, 如果键不存在则返回空字符串, 如果出现错误则返回错误
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(key, " Error getting key: %v", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// pop redis list from right,as stack
|
||||||
|
func PopRedisList(key string) string {
|
||||||
|
ctx := context.Background()
|
||||||
|
val, err := RedisClient.RPop(ctx, key).Result() // 从 Redis 读取键值, 如果键不存在则返回空字符串, 如果出现错误则返回错误
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(key, " Error reading from Redis: %v", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// pop redis list from left,as queue
|
||||||
|
func PopRedisListLeft(key string) string {
|
||||||
|
ctx := context.Background()
|
||||||
|
val, err := RedisClient.LPop(ctx, key).Result() // 从 Redis 读取键值, 如果键不存在则返回空字符串, 如果出现错误则返回错误
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
func DelRedis(key string) {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.Del(ctx, key).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error deleting key: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// push redis list from right
|
||||||
|
func PushRedisList(key string, value string) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.RPush(ctx, key, value).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.RPush(ctx, key, value).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
err = RedisClient.Expire(ctx, key, expire).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete redis key
|
||||||
|
func delRedis(key string) {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.Del(ctx, key).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// User 用户,用于存入 Redis hash
|
||||||
|
type RUser struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Age int `json:"age"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *RUser) toJSONString() string {
|
||||||
|
// 将User对象编码为JSON字符串
|
||||||
|
userJSON, err := json.Marshal(u)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to marshal user: %v", err)
|
||||||
|
}
|
||||||
|
return string(userJSON)
|
||||||
|
}
|
||||||
|
|
||||||
|
// put hash to redis
|
||||||
|
func hSetRedis(key string, field string, value string) {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.HSet(ctx, key, field, value).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get hash from redis
|
||||||
|
func hGetRedis(key string, field string) string {
|
||||||
|
ctx := context.Background()
|
||||||
|
val, err := RedisClient.HGet(ctx, key, field).Result()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error getting key: %v", err)
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置set,有过期时间
|
||||||
|
func SetRedisSet(key string, values []string, expire time.Duration) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.SAdd(ctx, key, values).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
err = RedisClient.Expire(ctx, key, expire).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置set,添加元素
|
||||||
|
func SetRedisSetAdd(key string, value string) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.SAdd(ctx, key, value).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
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,添加元素
|
||||||
|
func SetRedisSetAddWithExpire(key string, value string, expire time.Duration) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.SAdd(ctx, key, value).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("SetRedisSetAddWithExpire Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
err = RedisClient.Expire(ctx, key, expire).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("SetRedisSetAddWithExpire Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置set,删除元素
|
||||||
|
func SetRedisSetRemove(key string, value string) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.SRem(ctx, key, value).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取两个set的交集
|
||||||
|
func GetRedisSetIntersect(key1 string, key2 string) []string {
|
||||||
|
ctx := context.Background()
|
||||||
|
val, err := RedisClient.SInter(ctx, key1, key2).Result()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error getting key: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看set是否包含元素
|
||||||
|
func IsContainSet(key string, value string) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
val, err := RedisClient.SIsMember(ctx, key, value).Result()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error getting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看set的所有元素
|
||||||
|
func GetRedisSetMembers(key string) []string {
|
||||||
|
ctx := context.Background()
|
||||||
|
val, err := RedisClient.SMembers(ctx, key).Result()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error getting key: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// BITMAP
|
||||||
|
func SetRedisBitmap(key string, offset int64, value int) bool {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.SetBit(ctx, key, offset, value).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// BITMAP获取
|
||||||
|
func GetRedisBitmap(key string, offset int64) int {
|
||||||
|
ctx := context.Background()
|
||||||
|
val, err := RedisClient.GetBit(ctx, key, offset).Result()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error getting key: %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return int(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发布订阅者模式-发布消息
|
||||||
|
func Publish(channel string, message string, expire time.Duration) {
|
||||||
|
ctx := context.Background()
|
||||||
|
err := RedisClient.Publish(ctx, channel, message).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error publishing message: %v", err)
|
||||||
|
}
|
||||||
|
err = RedisClient.Expire(ctx, channel, expire).Err()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error setting key: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发布订阅者模式-订阅消息
|
||||||
|
func Subscribe(channel string) []string {
|
||||||
|
ctx := context.Background()
|
||||||
|
pubsub := RedisClient.Subscribe(ctx, channel)
|
||||||
|
ch := pubsub.Channel()
|
||||||
|
defer pubsub.Close()
|
||||||
|
var messages []string
|
||||||
|
for msg := range ch {
|
||||||
|
messages = append(messages, msg.Payload)
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,180 @@
|
||||||
|
package worker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"StuAcaWorksAI/proto"
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var client *http.Client
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
func InitReq() {
|
||||||
|
client = &http.Client{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发起post请求
|
||||||
|
func Post(url string, bodyType string, body string) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("POST", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", bodyType)
|
||||||
|
req.Body = io.NopCloser(strings.NewReader(body))
|
||||||
|
return client.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送到机器人
|
||||||
|
func SendToRobot(url string, body string) (map[string]interface{}, error) {
|
||||||
|
resp, err := Post(url, "application/json", body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
m := make(map[string]interface{})
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(&m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成补全的函数
|
||||||
|
func GenerateCompletion(url, prompt string, model string) (map[string]interface{}, error) {
|
||||||
|
data := map[string]interface{}{
|
||||||
|
"model": model,
|
||||||
|
"prompt": prompt,
|
||||||
|
"stream": false,
|
||||||
|
}
|
||||||
|
jsonData, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
client_ := &http.Client{}
|
||||||
|
resp, err := client_.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result map[string]interface{}
|
||||||
|
err = json.Unmarshal(body, &result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取数据,全量及增量
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package worker
|
||||||
|
|
||||||
|
import "math/rand"
|
||||||
|
|
||||||
|
func GetRandomString(l int) string {
|
||||||
|
str := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
bytes := []byte(str)
|
||||||
|
var result []byte
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
result = append(result, bytes[rand.Intn(len(bytes))])
|
||||||
|
}
|
||||||
|
return string(result)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue