im 管理后台
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
// Package global
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
package global
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/hgrds/lock"
|
||||
"hotgo/internal/library/hgrds/pubsub"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/utility/simple"
|
||||
)
|
||||
|
||||
// SubscribeClusterSync 订阅集群同步,可以用来集中同步数据、状态等
|
||||
func SubscribeClusterSync(ctx context.Context) {
|
||||
if !simple.IsCluster(ctx) {
|
||||
return
|
||||
}
|
||||
|
||||
err := pubsub.SubscribeMap(map[string]pubsub.SubHandler{
|
||||
consts.ClusterSyncSysconfig: service.SysConfig().ClusterSync, // 系统配置
|
||||
consts.ClusterSyncSysBlacklist: service.SysBlacklist().ClusterSync, // 系统黑名单
|
||||
consts.ClusterSyncSysSuperAdmin: service.AdminMember().ClusterSyncSuperAdmin, // 超管
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
g.Log().Fatal(ctx, err)
|
||||
}
|
||||
}
|
||||
|
||||
// PublishClusterSync 推送集群同步消息,如果没有开启集群部署,则不进行推送
|
||||
func PublishClusterSync(ctx context.Context, channel string, message interface{}) {
|
||||
if !simple.IsCluster(ctx) {
|
||||
return
|
||||
}
|
||||
|
||||
mutex := lock.Mutex(fmt.Sprintf("%s:%s", "lock", channel))
|
||||
err := mutex.LockFunc(ctx, func() {
|
||||
if _, err := pubsub.Publish(ctx, channel, message); err != nil {
|
||||
g.Log().Warningf(ctx, "PublishClusterSync %v err:%v", channel, err)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
g.Log().Warningf(ctx, "PublishClusterSync %v LockFunc err:%v", channel, err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Package global
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
package global
|
||||
|
||||
// 在这里可以配置一些全局公用的变量
|
||||
@@ -0,0 +1,125 @@
|
||||
// Package global
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2024 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
package global
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/util/gmeta"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
)
|
||||
|
||||
// HTTPRouter http路由
|
||||
type HTTPRouter struct {
|
||||
ghttp.RouterItem
|
||||
Tags string `json:"tags" dc:"接口所属的标签,用于接口分类"`
|
||||
Summary string `json:"summary" dc:"接口/参数概要描述"`
|
||||
Description string `json:"description" dc:"接口/参数详细描述"`
|
||||
}
|
||||
|
||||
var (
|
||||
httpRoutes map[string]*HTTPRouter
|
||||
routeMutex sync.Mutex
|
||||
shortTypeMapForTag = map[string]string{
|
||||
gtag.SummaryShort: gtag.Summary,
|
||||
gtag.SummaryShort2: gtag.Summary,
|
||||
gtag.DescriptionShort: gtag.Description,
|
||||
gtag.DescriptionShort2: gtag.Description,
|
||||
}
|
||||
)
|
||||
|
||||
// GetRequestRoute 获取当前请求路由属性
|
||||
func GetRequestRoute(r *ghttp.Request) *HTTPRouter {
|
||||
key := GenFilterRequestKey(r)
|
||||
routes := LoadHTTPRoutes(r)
|
||||
router, ok := routes[key]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return router
|
||||
}
|
||||
|
||||
// GenFilterRequestKey 根据请求生成唯一key
|
||||
func GenFilterRequestKey(r *ghttp.Request) string {
|
||||
return GenRouteKey(r.Method, r.Request.URL.Path)
|
||||
}
|
||||
|
||||
// GenFilterRouteKey 根据路由生成唯一key
|
||||
func GenFilterRouteKey(r *ghttp.Router) string {
|
||||
return GenRouteKey(r.Method, r.Uri)
|
||||
}
|
||||
|
||||
// GenRouteKey 生成唯一key
|
||||
func GenRouteKey(method, path string) string {
|
||||
return strings.ToUpper(method) + " " + path
|
||||
}
|
||||
|
||||
func LoadHTTPRoutes(r *ghttp.Request) map[string]*HTTPRouter {
|
||||
if httpRoutes == nil {
|
||||
routeMutex.Lock()
|
||||
defer routeMutex.Unlock()
|
||||
|
||||
if httpRoutes != nil {
|
||||
return httpRoutes
|
||||
}
|
||||
|
||||
httpRoutes = make(map[string]*HTTPRouter, len(r.Server.GetRoutes()))
|
||||
for _, v := range r.Server.GetRoutes() {
|
||||
key := GenFilterRouteKey(v.Handler.Router)
|
||||
if _, ok := httpRoutes[key]; !ok {
|
||||
router := new(HTTPRouter)
|
||||
router.RouterItem = v
|
||||
httpRoutes[key] = setRouterMeta(router)
|
||||
}
|
||||
}
|
||||
}
|
||||
return httpRoutes
|
||||
}
|
||||
|
||||
func setRouterMeta(router *HTTPRouter) *HTTPRouter {
|
||||
if !router.RouterItem.Handler.Info.IsStrictRoute {
|
||||
return router
|
||||
}
|
||||
|
||||
var reflectValue = reflect.ValueOf(router.Handler.Info.Value.Interface())
|
||||
for reflectValue.Kind() == reflect.Ptr {
|
||||
reflectValue = reflectValue.Elem()
|
||||
}
|
||||
|
||||
if reflectValue.Kind() != reflect.Func {
|
||||
return router
|
||||
}
|
||||
|
||||
var reflectType = reflect.TypeOf(router.Handler.Info.Value.Interface())
|
||||
if reflectType.NumIn() != 2 || reflectType.NumOut() != 2 {
|
||||
return router
|
||||
}
|
||||
|
||||
var inputObject reflect.Value
|
||||
if reflectType.In(1).Kind() == reflect.Ptr {
|
||||
inputObject = reflect.New(reflectType.In(1).Elem()).Elem()
|
||||
} else {
|
||||
inputObject = reflect.New(reflectType.In(1)).Elem()
|
||||
}
|
||||
|
||||
inputMetaMap := fillMapWithShortTags(gmeta.Data(inputObject.Interface()))
|
||||
router.Tags = inputMetaMap["tags"]
|
||||
router.Summary = inputMetaMap[gtag.Summary]
|
||||
router.Description = inputMetaMap[gtag.Description]
|
||||
return router
|
||||
}
|
||||
|
||||
func fillMapWithShortTags(m map[string]string) map[string]string {
|
||||
for k, v := range shortTypeMapForTag {
|
||||
if m[v] == "" && m[k] != "" {
|
||||
m[v] = m[k]
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
// Package global
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
package global
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/contrib/trace/jaeger/v2"
|
||||
"github.com/gogf/gf/v2"
|
||||
"github.com/gogf/gf/v2/container/gvar"
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gmode"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/cache"
|
||||
"hotgo/internal/library/queue"
|
||||
"hotgo/internal/model/entity"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/utility/charset"
|
||||
"hotgo/utility/simple"
|
||||
"hotgo/utility/validate"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Init(ctx context.Context) {
|
||||
// 设置gf运行模式
|
||||
SetGFMode(ctx)
|
||||
|
||||
// 设置服务日志处理
|
||||
glog.SetDefaultHandler(LoggingServeLogHandler)
|
||||
|
||||
// 默认上海时区
|
||||
if err := gtime.SetTimeZone("Asia/Shanghai"); err != nil {
|
||||
g.Log().Fatalf(ctx, "时区设置异常 err:%+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("欢迎使用HotGo!\r\n当前运行环境:%v, 运行根路径为:%v \r\nHotGo版本:v%v, gf版本:%v \n", runtime.GOOS, gfile.Pwd(), consts.VersionApp, gf.VERSION)
|
||||
|
||||
// 初始化链路追踪
|
||||
InitTrace(ctx)
|
||||
|
||||
// 设置缓存适配器
|
||||
cache.SetAdapter(ctx)
|
||||
|
||||
// 初始化功能库配置
|
||||
service.SysConfig().InitConfig(ctx)
|
||||
|
||||
// 加载超管数据
|
||||
service.AdminMember().LoadSuperAdmin(ctx)
|
||||
|
||||
// 订阅集群同步
|
||||
SubscribeClusterSync(ctx)
|
||||
}
|
||||
|
||||
// LoggingServeLogHandler 服务日志处理
|
||||
// 需要将异常日志保存到服务日志时可以通过SetHandlers设置此方法
|
||||
func LoggingServeLogHandler(ctx context.Context, in *glog.HandlerInput) {
|
||||
in.Next(ctx)
|
||||
|
||||
err := g.Try(ctx, func(ctx context.Context) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// web服务日志不做记录,因为会导致重复记录
|
||||
r := g.RequestFromCtx(ctx)
|
||||
if r != nil && r.Server != nil && in.Logger.GetConfig().Path == r.Server.Logger().GetConfig().Path {
|
||||
return
|
||||
}
|
||||
|
||||
conf, err := service.SysConfig().GetLoadServeLog(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if conf == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !conf.Switch {
|
||||
return
|
||||
}
|
||||
|
||||
if in.LevelFormat == "" || !gstr.InArray(conf.LevelFormat, in.LevelFormat) {
|
||||
return
|
||||
}
|
||||
|
||||
if in.Stack == "" {
|
||||
in.Stack = in.Logger.GetStack()
|
||||
}
|
||||
|
||||
if len(in.Content) == 0 {
|
||||
in.Content = gstr.StrLimit(gvar.New(in.Values).String(), consts.MaxServeLogContentLen)
|
||||
}
|
||||
|
||||
var data entity.SysServeLog
|
||||
data.TraceId = gctx.CtxId(ctx)
|
||||
data.LevelFormat = in.LevelFormat
|
||||
data.Content = in.Content
|
||||
data.Stack = gjson.New(charset.ParseStack(in.Stack))
|
||||
data.Line = strings.TrimRight(in.CallerPath, ":")
|
||||
data.TriggerNs = in.Time.UnixNano()
|
||||
data.Status = consts.StatusEnabled
|
||||
|
||||
if gstr.Contains(in.Content, `exception recovered`) {
|
||||
data.LevelFormat = "PANI"
|
||||
}
|
||||
|
||||
if data.Stack.IsNil() {
|
||||
data.Stack = gjson.New(consts.NilJsonToString)
|
||||
}
|
||||
|
||||
if conf.Queue {
|
||||
err = queue.Push(consts.QueueServeLogTopic, data)
|
||||
} else {
|
||||
err = service.SysServeLog().RealWrite(ctx, data)
|
||||
}
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
g.Dump("LoggingServeLogHandler err:", err)
|
||||
}
|
||||
}
|
||||
|
||||
// InitTrace 初始化链路追踪
|
||||
func InitTrace(ctx context.Context) {
|
||||
if !g.Cfg().MustGet(ctx, "jaeger.switch").Bool() {
|
||||
return
|
||||
}
|
||||
|
||||
tp, err := jaeger.Init(simple.AppName(ctx), g.Cfg().MustGet(ctx, "jaeger.endpoint").String())
|
||||
if err != nil {
|
||||
g.Log().Fatal(ctx, err)
|
||||
}
|
||||
|
||||
simple.Event().Register(consts.EventServerClose, func(ctx context.Context, args ...interface{}) {
|
||||
_ = tp.Shutdown(ctx)
|
||||
g.Log().Debug(ctx, "jaeger closed ..")
|
||||
})
|
||||
}
|
||||
|
||||
// SetGFMode 设置gf运行模式
|
||||
func SetGFMode(ctx context.Context) {
|
||||
mode := g.Cfg().MustGet(ctx, "system.mode").String()
|
||||
if len(mode) == 0 {
|
||||
mode = gmode.NOT_SET
|
||||
}
|
||||
|
||||
var modes = []string{gmode.DEVELOP, gmode.TESTING, gmode.STAGING, gmode.PRODUCT}
|
||||
|
||||
// 如果是有效的运行模式,就进行设置
|
||||
if validate.InSlice(modes, mode) {
|
||||
gmode.Set(mode)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user