videoplayer/main.go

408 lines
11 KiB
Go
Raw Normal View History

package main
import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt"
"github.com/robfig/cron/v3"
"io"
"log"
2024-12-06 19:33:52 +08:00
"net/http"
"os"
2024-12-16 21:31:56 +08:00
"strconv"
"strings"
"videoplayer/dao"
"videoplayer/handler"
"videoplayer/proto"
"videoplayer/service"
"videoplayer/worker"
)
func main() {
2025-08-02 15:39:32 +08:00
// 输入参数
if len(os.Args) > 1 {
initConfig(os.Args[1]) //第一个参数是配置文件路径
} else {
initConfig("") //没有输入参数,则使用默认配置文件路径
}
gin.SetMode(gin.ReleaseMode)
2024-09-27 21:13:56 +08:00
r := gin.Default()
2024-08-02 10:30:41 +08:00
err := dao.Init()
if err != nil {
panic("failed to connect database:" + err.Error())
}
2025-09-13 13:49:20 +08:00
if proto.Config.MEMORY_CACHE == false { //不开启内存缓存才使用redis
err = worker.InitRedis()
if err != nil {
panic("failed to connect redis:" + err.Error())
}
2024-08-02 10:30:41 +08:00
}
r.Use(handler.CrosHandler())
2025-06-01 16:34:37 +08:00
r.Use(JWTAuthMiddleware()) // 使用 JWT 认证中间件
handler.SetUpVideoGroup(r) // Video
//handler.SetUpUserGroup(r) // User
2024-06-27 10:53:47 +08:00
handler.SetUpDeviceGroup(r) // Device
handler.SetUpIMGroup(r) // IM
handler.SetUpCIDGroup(r) // CID,持续集成、部署
handler.SetUpToolGroup(r) // Tool
handler.SetUpFileGroup(r) // File
2025-02-22 14:44:53 +08:00
handler.SetUpShellGroup(r) // Shell
2025-08-19 22:43:31 +08:00
handler.SetDBManageGroup(r) // DBM
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
}
2025-08-02 15:49:35 +08:00
// 不使用
//
// 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/videoplayer/vp.conf
// configPath := "/home/videoplayer/vp.conf"
// //读取配置文件
// err := proto.ReadConfig(configPath)
// if err != nil {
// panic("failed to read config file:" + err.Error())
// }
// }
2025-08-02 15:39:32 +08:00
func initConfig(configPath string) {
2025-08-02 15:49:35 +08:00
//if proto.Config.TOKEN_SECRET != "" {
// return
//}
2025-08-02 15:39:32 +08:00
// 创建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)
//系统是linux、macos还是windows
if configPath == "" {
if os.Getenv("OS") == "Windows_NT" {
configPath = "C:/Users/Administrator/vp.conf"
} else if os.Getenv("OS") == "linux" {
//文件地址/home/saw-ai/saw-ai.conf
configPath = "/etc/vp.conf"
} else {
configPath = "/etc/vp.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 := ""
2024-08-30 15:03:33 +08:00
if method == "GET" {
params = c.Request.URL.RawQuery
}
2024-08-30 15:03:33 +08:00
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)
}
}
2024-08-30 15:03:33 +08:00
if strings.Contains(c.Request.URL.Path, "/upload") {
params = "upload file"
}
go dao.InsertLogToDB(path, ip, method, params)
2024-06-09 14:22:54 +08:00
}
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
2025-06-03 13:44:32 +08:00
//for k, _ := range proto.Url_map {
// if strings.Contains(c.Request.URL.Path, k) {
// c.Next()
// return
// }
//}
if proto.Url_map[c.Request.URL.Path] == true { //查看是否在不需要token的url中
c.Next()
return
}
2025-08-10 13:59:43 +08:00
if proto.SigningKeyIsValid == false {
c.AbortWithStatusJSON(http.StatusOK, gin.H{"message": "server error", "error": "token secret is invalid", "code": proto.SigningKeyIsValid})
return
}
if tokenString == "" {
//c.AbortWithStatus(200)
2025-08-10 13:59:43 +08:00
c.JSON(http.StatusOK, gin.H{"message": "Unauthorized", "error": "token is empty", "code": proto.TokenIsNull})
return
}
2024-09-22 13:59:33 +08:00
if proto.Config.TOKEN_USE_REDIS {
redisToken := worker.GetRedis(tokenString)
if redisToken == "" {
2025-06-02 17:58:12 +08:00
c.AbortWithStatusJSON(http.StatusOK, gin.H{"message": "NOT_LOGIN", "error": "server token is empty", "code": proto.TokenIsNull})
2024-09-22 13:59:33 +08:00
return
}
}
2025-03-05 19:54:31 +08:00
2024-12-04 16:07:51 +08:00
//查看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 == "" {
2025-06-02 17:58:12 +08:00
c.AbortWithStatusJSON(http.StatusOK, gin.H{"message": "unauthorized", "error": "super_id is empty", "code": proto.TokenIsNull})
2025-03-05 19:45:33 +08:00
return
}
id, _ := strconv.Atoi(sId)
idFloat64 := float64(id)
2024-12-16 21:31:56 +08:00
//查看s_id类型
c.Set("id", idFloat64)
2024-12-04 16:07:51 +08:00
c.Next()
return
}
2025-07-31 21:03:49 +08:00
proto.SigningKeyRWLock.RLock() //加读锁
2024-09-22 13:59:33 +08:00
// 使用加密secret 解析 JWT 令牌
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
2024-09-22 13:59:33 +08:00
return proto.SigningKey, nil
})
2025-07-31 21:03:49 +08:00
proto.SigningKeyRWLock.RUnlock()
// 验证令牌
if err != nil || !token.Valid {
2025-06-02 17:58:12 +08:00
c.AbortWithStatusJSON(http.StatusOK, 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"])
2024-12-04 18:39:57 +08:00
if UserFuncIntercept(int(token.Claims.(jwt.MapClaims)["id"].(float64)), c.Request.URL.Path) {
2025-06-02 17:58:12 +08:00
c.AbortWithStatusJSON(http.StatusOK, gin.H{
2024-12-04 18:39:57 +08:00
"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()
2025-02-22 14:44:26 +08:00
service.ShellWillRunFromServer()
2025-07-31 21:03:49 +08:00
service.SyncTokenSecretFromUserCenter()
2025-09-09 20:45:04 +08:00
service.DelDBMMap() //定时处理DBMMap中的数据
2025-09-13 13:49:20 +08:00
if proto.Config.MEMORY_CACHE {
worker.DeleteMemoryCacheCron()
// 清理后持久化
worker.WriteMemoryCacheToFile()
}
}
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 {
2024-12-04 19:09:08 +08:00
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)
}
}
2024-12-15 17:45:31 +08:00
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
2024-12-15 17:45:31 +08:00
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
2024-12-04 19:13:38 +08:00
json_data, err := json.Marshal(cron_infos)
if err != nil {
2024-12-04 19:13:38 +08:00
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 != "" {
2024-12-04 19:16:13 +08:00
err := json.Unmarshal([]byte(res), &cron_infos)
if err != nil {
2024-12-04 19:09:08 +08:00
fmt.Println("RunGeneralCron Error decoding config,key value is :", res)
}
2024-12-15 17:38:35 +08:00
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
}
2024-12-15 17:38:35 +08:00
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
}
2024-12-15 17:38:35 +08:00
cron_infos[i] = v
continue
}
}
//存入redis
2024-12-04 19:13:38 +08:00
json_data, err := json.Marshal(cron_infos)
if err != nil {
2024-12-04 19:09:08 +08:00
fmt.Println("RunGeneralCron Error encoding config,value is :", cron_infos)
2024-12-04 19:13:38 +08:00
} else {
worker.SetRedis(key, string(json_data))
}
}
}
2024-12-04 18:39:57 +08:00
// 用户功能拦截,返回true表示拦截false表示不拦截
func UserFuncIntercept(id int, url string) bool {
//先查看是否有权限
2025-06-01 16:34:37 +08:00
user := service.GetUserByIDFromUserCenter(id)
2024-12-04 18:39:57 +08:00
//如果用户有权限,则不拦截
for k, v := range proto.Per_menu_map {
if strings.Contains(url, k) {
2025-10-18 22:35:02 +08:00
if v == 1 && user.VideoFunc > 0 {
2024-12-04 19:23:57 +08:00
return true
2024-12-04 18:39:57 +08:00
}
2025-10-18 22:35:02 +08:00
if v == 2 && user.DeviceFunc > 0 {
2024-12-04 19:23:57 +08:00
return true
2024-12-04 18:39:57 +08:00
}
2025-10-18 22:35:02 +08:00
if v == 3 && user.CIDFunc > 0 {
2024-12-04 19:23:57 +08:00
return true
2024-12-04 18:39:57 +08:00
}
}
}
2024-12-04 19:23:57 +08:00
return false
2024-12-04 18:39:57 +08:00
}