videoplayer/main.go

304 lines
7.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt"
"github.com/robfig/cron/v3"
"io"
"log"
"os"
"strings"
"videoplayer/dao"
"videoplayer/handler"
"videoplayer/proto"
"videoplayer/worker"
)
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.SetUpVideoGroup(r) // Video
handler.SetUpUserGroup(r) // User
handler.SetUpDeviceGroup(r) // Device
handler.SetUpIMGroup(r) // IM
handler.SetUpCIDGroup(r) // CID,持续集成、部署
handler.SetUpToolGroup(r) // Tool
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/videoplayer/vp.conf
configPath := "/home/videoplayer/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 := ""
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) {
s_id := c.Request.Header.Get("super_id")
if s_id == "" {
c.AbortWithStatus(200)
c.JSON(200, gin.H{
"message": "NOT_LOGIN",
"error": "super_id is empty",
"code": proto.TokenIsNull,
})
return
}
c.Set("id", s_id)
c.Next()
return
}
// 使用加密secret 解析 JWT 令牌
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return proto.SigningKey, nil
})
// 验证令牌
if err != nil || !token.Valid {
c.AbortWithStatus(200)
c.JSON(200, gin.H{
"message": "NOT_LOGIN",
"error": "Invalid token",
"code": 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(200, 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添加通用定时任务
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)
}
}
} 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)
}
}
//存入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 _, 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
}
}
}
//存入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 == true {
return false
}
if v == 2 && user.DeviceFunc == true {
return false
}
if v == 3 && user.CIDFunc == true {
return false
}
}
}
if strings.Contains(url, "/callback") {
return false
}
return true
}