mirror of
https://github.com/bufanyun/hotgo.git
synced 2026-04-24 12:04:36 +08:00
发布v2.2.10版本,更新内容请查看:https://github.com/bufanyun/hotgo/tree/v2.0/docs/guide-zh-CN/addon-version-upgrade.md
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// Package cmd
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -41,7 +41,7 @@ var (
|
||||
---------------------------------------------------------------------------------
|
||||
更多
|
||||
github地址:https://github.com/bufanyun/hotgo
|
||||
文档地址:文档正在书写中,请耐心等一等。
|
||||
文档地址:https://github.com/bufanyun/hotgo/tree/v2.0/docs
|
||||
HotGo框架交流1群:190966648
|
||||
`,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package cmd
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Package cmd
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package cmd
|
||||
|
||||
import (
|
||||
@@ -11,6 +10,7 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"hotgo/internal/library/addons"
|
||||
"hotgo/internal/library/casbin"
|
||||
"hotgo/internal/router"
|
||||
"hotgo/internal/service"
|
||||
@@ -36,8 +36,7 @@ var (
|
||||
})
|
||||
|
||||
// 请求结束事件回调
|
||||
s.BindHookHandler("/*any", ghttp.HookAfterOutput, service.Hook().AccessLog)
|
||||
s.BindHookHandler("/*any", ghttp.HookAfterOutput, service.Hook().LastActive)
|
||||
s.BindHookHandler("/*any", ghttp.HookAfterOutput, service.Hook().AfterOutput)
|
||||
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
|
||||
@@ -61,6 +60,9 @@ var (
|
||||
|
||||
// 注册前台页面路由
|
||||
router.Home(ctx, group)
|
||||
|
||||
// 注册插件路由
|
||||
addons.RegisterModulesRouter(ctx, group)
|
||||
})
|
||||
|
||||
// 启动定时任务
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package cmd
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package cmd
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
51
server/internal/consts/addons.go
Normal file
51
server/internal/consts/addons.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package consts
|
||||
|
||||
const (
|
||||
AddonsTag = "addons_" // 插件标签前缀
|
||||
AddonsDir = "addons" // 插件路径
|
||||
)
|
||||
|
||||
const (
|
||||
AddonsGroupPlug = 1 // 功能扩展
|
||||
AddonsGroupBusiness = 2 // 主要业务
|
||||
AddonsGroupThirdParty = 3 // 第三方插件
|
||||
AddonsGroupMiniApp = 4 // 小程序
|
||||
AddonsGroupCustomer = 5 // 客户关系
|
||||
AddonsGroupActivity = 6 // 营销及活动
|
||||
AddonsGroupServices = 7 // 常用服务及工具
|
||||
AddonsGroupBiz = 8 // 行业解决方案
|
||||
)
|
||||
|
||||
var AddonsGroupNameMap = map[int]string{
|
||||
AddonsGroupPlug: "功能扩展",
|
||||
AddonsGroupBusiness: "主要业务",
|
||||
AddonsGroupThirdParty: "第三方插件",
|
||||
AddonsGroupMiniApp: "小程序",
|
||||
AddonsGroupCustomer: "客户关系",
|
||||
AddonsGroupActivity: "营销及活动",
|
||||
AddonsGroupServices: "常用服务及工具",
|
||||
AddonsGroupBiz: "行业解决方案",
|
||||
}
|
||||
|
||||
var AddonsGroupIconMap = map[int]string{
|
||||
AddonsGroupPlug: "AppstoreAddOutlined",
|
||||
AddonsGroupBusiness: "FireOutlined",
|
||||
AddonsGroupThirdParty: "ApiOutlined",
|
||||
AddonsGroupMiniApp: "RocketOutlined",
|
||||
AddonsGroupCustomer: "UserSwitchOutlined",
|
||||
AddonsGroupActivity: "TagOutlined",
|
||||
AddonsGroupServices: "ToolOutlined",
|
||||
AddonsGroupBiz: "CheckCircleOutlined",
|
||||
}
|
||||
|
||||
const (
|
||||
AddonsInstallStatusOk = 1 // 已安装
|
||||
AddonsInstallStatusNo = 2 // 未安装
|
||||
AddonsInstallStatusUn = 3 // 已卸载
|
||||
)
|
||||
|
||||
var AddonsInstallStatusNameMap = map[int]string{
|
||||
AddonsInstallStatusOk: "已安装",
|
||||
AddonsInstallStatusNo: "未安装",
|
||||
AddonsInstallStatusUn: "已卸载",
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
// Package consts
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package consts
|
||||
|
||||
// 应用类型
|
||||
const (
|
||||
AppAdmin = "admin"
|
||||
AppApi = "api"
|
||||
AppDefault = "default"
|
||||
AppAdmin = "admin"
|
||||
AppApi = "api"
|
||||
AppHome = "home"
|
||||
AppWebSocket = "websocket"
|
||||
AppDefault = "default"
|
||||
)
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
// Package consts
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package consts
|
||||
|
||||
// redis
|
||||
// cache
|
||||
const (
|
||||
RedisJwtToken = "jwtToken:" // JWT-token
|
||||
RedisJwtUserBind = "jwtUserBind:" // JWT-用户身份绑定
|
||||
CacheJwtToken = "jwt_token:" // JWT-token
|
||||
CacheJwtUserBind = "jwt_user_bind:" // JWT-用户身份绑定
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package consts
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package consts
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package consts
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package consts
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package consts
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package consts
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package consts
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package consts
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package consts
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package consts
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// Package consts
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package consts
|
||||
|
||||
// VersionApp HotGo版本
|
||||
const (
|
||||
VersionApp = "2.1.3"
|
||||
VersionApp = "2.2.10"
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package admin
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,7 +9,7 @@ package admin
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/dept"
|
||||
"hotgo/api/admin/dept"
|
||||
"hotgo/internal/model/input/adminin"
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package admin
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/member"
|
||||
"hotgo/api/admin/member"
|
||||
"hotgo/internal/library/contexts"
|
||||
"hotgo/internal/model/input/adminin"
|
||||
"hotgo/internal/model/input/form"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package admin
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,7 +9,7 @@ package admin
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/menu"
|
||||
"hotgo/api/admin/menu"
|
||||
"hotgo/internal/model/input/adminin"
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package admin
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"hotgo/api/backend/monitor"
|
||||
"hotgo/api/admin/monitor"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/websocket"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package admin
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,7 +9,7 @@ package admin
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/notice"
|
||||
"hotgo/api/admin/notice"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model/input/adminin"
|
||||
"hotgo/internal/model/input/form"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package admin
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,7 +9,7 @@ package admin
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/post"
|
||||
"hotgo/api/admin/post"
|
||||
"hotgo/internal/model/input/adminin"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/service"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package admin
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,7 +9,7 @@ package admin
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/role"
|
||||
"hotgo/api/admin/role"
|
||||
"hotgo/internal/library/contexts"
|
||||
"hotgo/internal/model/input/adminin"
|
||||
"hotgo/internal/model/input/form"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package common
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -8,7 +8,7 @@ package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"hotgo/api/backend/common"
|
||||
"hotgo/api/admin/common"
|
||||
)
|
||||
|
||||
var Console = cConsole{}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package common
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"hotgo/api/backend/common"
|
||||
"hotgo/api/admin/common"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/contexts"
|
||||
"hotgo/internal/model/entity"
|
||||
@@ -1,19 +1,18 @@
|
||||
// Package common
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/crypto/gmd5"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/common"
|
||||
"hotgo/api/admin/common"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/cache"
|
||||
"hotgo/internal/library/captcha"
|
||||
@@ -21,6 +20,7 @@ import (
|
||||
"hotgo/internal/model/input/adminin"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/utility/validate"
|
||||
)
|
||||
|
||||
var Site = cSite{}
|
||||
@@ -34,29 +34,43 @@ func (c *cSite) Ping(ctx context.Context, req *common.SitePingReq) (res *common.
|
||||
|
||||
// Config 获取配置
|
||||
func (c *cSite) Config(ctx context.Context, req *common.SiteConfigReq) (res *common.SiteConfigRes, err error) {
|
||||
request := ghttp.RequestFromCtx(ctx)
|
||||
res = &common.SiteConfigRes{
|
||||
Version: consts.VersionApp,
|
||||
WsAddr: c.getWsAddr(ctx),
|
||||
WsAddr: c.getWsAddr(ctx, request),
|
||||
Domain: c.getDomain(ctx, request),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *cSite) getWsAddr(ctx context.Context) string {
|
||||
ws := g.Cfg().MustGet(ctx, "hotgo.wsAddr", "ws://127.0.0.1:8000/socket")
|
||||
return ws.String()
|
||||
func (c *cSite) getWsAddr(ctx context.Context, request *ghttp.Request) string {
|
||||
// 如果是本地IP访问,则认为是调试模式,走实际请求地址,否则走配置中的地址
|
||||
ip := ghttp.RequestFromCtx(ctx).GetHeader("hostname")
|
||||
if validate.IsLocalIPAddr(ip) {
|
||||
return "ws://" + ip + ":" + gstr.StrEx(request.Host, ":") + "/socket"
|
||||
}
|
||||
|
||||
//// nginx负载均衡部署
|
||||
//// 如果是IP访问,则认为是调试模式,走配置中的ws地址,否则走实际请求中的域名+协议
|
||||
//if !validate.IsDNSName(ghttp.RequestFromCtx(ctx).Host) {
|
||||
// ws := g.Cfg().MustGet(ctx, "hotgo.wsAddr", "ws://127.0.0.1:8000/socket")
|
||||
// return ws.String()
|
||||
//}
|
||||
//
|
||||
//if !validate.IsHTTPS(ctx) {
|
||||
// return fmt.Sprintf("ws://%s/socket", url.GetDomain(ctx))
|
||||
//}
|
||||
//
|
||||
//return fmt.Sprintf("wss://%s/socket", url.GetDomain(ctx))
|
||||
basic, err := service.SysConfig().GetBasic(ctx)
|
||||
if err != nil || basic == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return basic.WsAddr
|
||||
}
|
||||
|
||||
func (c *cSite) getDomain(ctx context.Context, request *ghttp.Request) string {
|
||||
// 如果是本地IP访问,则认为是调试模式,走实际请求地址,否则走配置中的地址
|
||||
ip := request.GetHeader("hostname")
|
||||
if validate.IsLocalIPAddr(ip) {
|
||||
return "http://" + ip + ":" + gstr.StrEx(request.Host, ":")
|
||||
}
|
||||
|
||||
basic, err := service.SysConfig().GetBasic(ctx)
|
||||
if err != nil || basic == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return basic.Domain
|
||||
}
|
||||
|
||||
// Captcha 登录验证码
|
||||
@@ -98,14 +112,13 @@ func (c *cSite) Login(ctx context.Context, req *common.LoginReq) (res *common.Lo
|
||||
|
||||
// Logout 注销登录
|
||||
func (c *cSite) Logout(ctx context.Context, req *common.LoginLogoutReq) (res *common.LoginLogoutRes, err error) {
|
||||
token := consts.RedisJwtToken + gmd5.MustEncryptString(jwt.GetAuthorization(ghttp.RequestFromCtx(ctx)))
|
||||
token := consts.CacheJwtToken + gmd5.MustEncryptString(jwt.GetAuthorization(ghttp.RequestFromCtx(ctx)))
|
||||
if len(token) == 0 {
|
||||
err = gerror.New("当前用户未登录!")
|
||||
return res, err
|
||||
return
|
||||
}
|
||||
|
||||
// 删除登录token
|
||||
ca := cache.New()
|
||||
_, err = ca.Remove(ctx, token)
|
||||
_, err = cache.Instance().Remove(ctx, token)
|
||||
return
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package common
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/common"
|
||||
"hotgo/api/admin/common"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/contexts"
|
||||
"hotgo/internal/model/entity"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package common
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"hotgo/api/backend/common"
|
||||
"hotgo/api/admin/common"
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
|
||||
108
server/internal/controller/admin/sys/addons.go
Normal file
108
server/internal/controller/admin/sys/addons.go
Normal file
@@ -0,0 +1,108 @@
|
||||
// Package sys
|
||||
// @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 sys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/admin/addons"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/utility/validate"
|
||||
)
|
||||
|
||||
var (
|
||||
Addons = cAddons{}
|
||||
)
|
||||
|
||||
type cAddons struct{}
|
||||
|
||||
// List 查看列表
|
||||
func (c *cAddons) List(ctx context.Context, req *addons.ListReq) (res *addons.ListRes, err error) {
|
||||
var in sysin.AddonsListInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
list, totalCount, err := service.SysAddons().List(ctx, in)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = new(addons.ListRes)
|
||||
res.List = list
|
||||
res.PageCount = form.CalPageCount(totalCount, req.PerPage)
|
||||
res.Page = req.Page
|
||||
res.PerPage = req.PerPage
|
||||
return
|
||||
}
|
||||
|
||||
// Selects 获取指定信息
|
||||
func (c *cAddons) Selects(ctx context.Context, req *addons.SelectsReq) (res *addons.SelectsRes, err error) {
|
||||
data, err := service.SysAddons().Selects(ctx, sysin.AddonsSelectsInp{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = new(addons.SelectsRes)
|
||||
res.AddonsSelectsModel = data
|
||||
return
|
||||
}
|
||||
|
||||
// Build 生成预览
|
||||
func (c *cAddons) Build(ctx context.Context, req *addons.BuildReq) (res *addons.BuildRes, err error) {
|
||||
var in sysin.AddonsBuildInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = validate.PreFilter(ctx, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = service.SysAddons().Build(ctx, in)
|
||||
return
|
||||
}
|
||||
|
||||
// Install 安装模块
|
||||
func (c *cAddons) Install(ctx context.Context, req *addons.InstallReq) (res *addons.InstallRes, err error) {
|
||||
var in sysin.AddonsInstallInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = service.SysAddons().Install(ctx, in); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Upgrade 更新模块
|
||||
func (c *cAddons) Upgrade(ctx context.Context, req *addons.UpgradeReq) (res *addons.UpgradeRes, err error) {
|
||||
var in sysin.AddonsUpgradeInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = service.SysAddons().Upgrade(ctx, in); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// UnInstall 卸载模块
|
||||
func (c *cAddons) UnInstall(ctx context.Context, req *addons.UnInstallReq) (res *addons.UnInstallRes, err error) {
|
||||
var in sysin.AddonsUnInstallInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = service.SysAddons().UnInstall(ctx, in); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package sys
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,7 +9,7 @@ package sys
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/attachment"
|
||||
"hotgo/api/admin/attachment"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package sys
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,7 +9,7 @@ package sys
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/blacklist"
|
||||
"hotgo/api/admin/blacklist"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package sys
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,7 +9,7 @@ package sys
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/config"
|
||||
"hotgo/api/admin/config"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package sys
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/cron"
|
||||
"hotgo/api/admin/cron"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package sys
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,7 +9,7 @@ package sys
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/cron"
|
||||
"hotgo/api/admin/cron"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
@@ -3,14 +3,14 @@
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
// @AutoGenerate Version 2.1.2
|
||||
// @AutoGenerate Date 2023-02-08 17:47:32
|
||||
// @AutoGenerate Version 2.1.4
|
||||
// @AutoGenerate Date 2023-02-20 16:41:58
|
||||
//
|
||||
package sys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"hotgo/api/backend/curddemo"
|
||||
"hotgo/api/admin/curddemo"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
@@ -29,16 +29,16 @@ type cCurdDemo struct{}
|
||||
func (c *cCurdDemo) List(ctx context.Context, req *curddemo.ListReq) (res *curddemo.ListRes, err error) {
|
||||
var in sysin.CurdDemoListInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
if err = validate.PreFilter(ctx, &in); err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
list, totalCount, err := service.SysCurdDemo().List(ctx, in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
res = new(curddemo.ListRes)
|
||||
@@ -46,123 +46,113 @@ func (c *cCurdDemo) List(ctx context.Context, req *curddemo.ListReq) (res *curdd
|
||||
res.PageCount = form.CalPageCount(totalCount, req.PerPage)
|
||||
res.Page = req.Page
|
||||
res.PerPage = req.PerPage
|
||||
return res, nil
|
||||
return
|
||||
}
|
||||
|
||||
// Export 导出生成演示列表
|
||||
func (c *cCurdDemo) Export(ctx context.Context, req *curddemo.ExportReq) (res *curddemo.ExportRes, err error) {
|
||||
var in sysin.CurdDemoListInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
if err = validate.PreFilter(ctx, &in); err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
if err = service.SysCurdDemo().Export(ctx, in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
err = service.SysCurdDemo().Export(ctx, in)
|
||||
return
|
||||
}
|
||||
|
||||
// Edit 更新生成演示
|
||||
func (c *cCurdDemo) Edit(ctx context.Context, req *curddemo.EditReq) (res *curddemo.EditRes, err error) {
|
||||
var in sysin.CurdDemoEditInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
if err = validate.PreFilter(ctx, &in); err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
if err = service.SysCurdDemo().Edit(ctx, in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
err = service.SysCurdDemo().Edit(ctx, in)
|
||||
return
|
||||
}
|
||||
|
||||
// MaxSort 获取生成演示最大排序
|
||||
func (c *cCurdDemo) MaxSort(ctx context.Context, req *curddemo.MaxSortReq) (res *curddemo.MaxSortRes, err error) {
|
||||
data, err := service.SysCurdDemo().MaxSort(ctx, sysin.CurdDemoMaxSortInp{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
res = new(curddemo.MaxSortRes)
|
||||
res.CurdDemoMaxSortModel = data
|
||||
return res, nil
|
||||
return
|
||||
}
|
||||
|
||||
// View 获取指定生成演示信息
|
||||
func (c *cCurdDemo) View(ctx context.Context, req *curddemo.ViewReq) (res *curddemo.ViewRes, err error) {
|
||||
var in sysin.CurdDemoViewInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
if err = validate.PreFilter(ctx, &in); err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
data, err := service.SysCurdDemo().View(ctx, in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
res = new(curddemo.ViewRes)
|
||||
res.CurdDemoViewModel = data
|
||||
return res, nil
|
||||
return
|
||||
}
|
||||
|
||||
// Delete 删除生成演示
|
||||
func (c *cCurdDemo) Delete(ctx context.Context, req *curddemo.DeleteReq) (res *curddemo.DeleteRes, err error) {
|
||||
var in sysin.CurdDemoDeleteInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
if err = validate.PreFilter(ctx, &in); err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
if err = service.SysCurdDemo().Delete(ctx, in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
err = service.SysCurdDemo().Delete(ctx, in)
|
||||
return
|
||||
}
|
||||
|
||||
// Status 更新生成演示状态
|
||||
func (c *cCurdDemo) Status(ctx context.Context, req *curddemo.StatusReq) (res *curddemo.StatusRes, err error) {
|
||||
var in sysin.CurdDemoStatusInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
if err = validate.PreFilter(ctx, &in); err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
if err = service.SysCurdDemo().Status(ctx, in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
err = service.SysCurdDemo().Status(ctx, in)
|
||||
return
|
||||
}
|
||||
|
||||
// Switch 更新生成演示开关状态
|
||||
func (c *cCurdDemo) Switch(ctx context.Context, req *curddemo.SwitchReq) (res *curddemo.SwitchRes, err error) {
|
||||
var in sysin.CurdDemoSwitchInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
if err = validate.PreFilter(ctx, &in); err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
if err = service.SysCurdDemo().Switch(ctx, in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
err = service.SysCurdDemo().Switch(ctx, in)
|
||||
return
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package sys
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,7 +9,7 @@ package sys
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/dict"
|
||||
"hotgo/api/admin/dict"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package sys
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,7 +9,7 @@ package sys
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/dict"
|
||||
"hotgo/api/admin/dict"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package sys
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,7 +9,7 @@ package sys
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/emslog"
|
||||
"hotgo/api/admin/emslog"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package sys
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,10 +9,11 @@ package sys
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/gencodes"
|
||||
"hotgo/api/admin/gencodes"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/utility/validate"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -39,6 +40,10 @@ func (c *cGenCodes) Edit(ctx context.Context, req *gencodes.EditReq) (res *genco
|
||||
return
|
||||
}
|
||||
|
||||
if err = validate.PreFilter(ctx, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := service.SysGenCodes().Edit(ctx, in)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -161,6 +166,10 @@ func (c *cGenCodes) Preview(ctx context.Context, req *gencodes.PreviewReq) (res
|
||||
return
|
||||
}
|
||||
|
||||
if err = validate.PreFilter(ctx, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := service.SysGenCodes().Preview(ctx, in)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -178,6 +187,10 @@ func (c *cGenCodes) Build(ctx context.Context, req *gencodes.BuildReq) (res *gen
|
||||
return
|
||||
}
|
||||
|
||||
if err = validate.PreFilter(ctx, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = service.SysGenCodes().Build(ctx, in)
|
||||
return
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package sys
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/log"
|
||||
"hotgo/api/admin/log"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
@@ -11,7 +11,7 @@ package sys
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/loginlog"
|
||||
"hotgo/api/admin/loginlog"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package sys
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,7 +9,7 @@ package sys
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/provinces"
|
||||
"hotgo/api/admin/provinces"
|
||||
"hotgo/internal/library/location"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
@@ -9,7 +9,7 @@ package sys
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/servelog"
|
||||
"hotgo/api/admin/servelog"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package sys
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -9,7 +9,7 @@ package sys
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/smslog"
|
||||
"hotgo/api/admin/smslog"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
@@ -93,7 +93,7 @@ func (c *cSmsLog) Status(ctx context.Context, req *smslog.StatusReq) (res *smslo
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
err = service.SysSmsLog().Status(ctx, in)
|
||||
return
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package member
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package user
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -8,9 +8,8 @@ package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"hotgo/api/api/user"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"hotgo/api/api/user"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
// Package admin
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/api/backend/test"
|
||||
"hotgo/internal/model/input/adminin"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/utility/validate"
|
||||
)
|
||||
|
||||
var (
|
||||
Test = cTest{}
|
||||
)
|
||||
|
||||
type cTest struct{}
|
||||
|
||||
// List 查看列表
|
||||
func (c *cTest) List(ctx context.Context, req *test.ListReq) (res *test.ListRes, err error) {
|
||||
var in adminin.TestListInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = validate.PreFilter(ctx, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
list, totalCount, err := service.AdminTest().List(ctx, in)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = new(test.ListRes)
|
||||
res.List = list
|
||||
res.PageCount = form.CalPageCount(totalCount, req.PerPage)
|
||||
res.Page = req.Page
|
||||
res.PerPage = req.PerPage
|
||||
return
|
||||
}
|
||||
|
||||
// Export 导出列表
|
||||
func (c *cTest) Export(ctx context.Context, req *test.ExportReq) (res *test.ExportRes, err error) {
|
||||
var in adminin.TestListInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = service.AdminTest().Export(ctx, in)
|
||||
return
|
||||
}
|
||||
|
||||
// Edit 更新
|
||||
func (c *cTest) Edit(ctx context.Context, req *test.EditReq) (res *test.EditRes, err error) {
|
||||
var in adminin.TestEditInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = validate.PreFilter(ctx, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = service.AdminTest().Edit(ctx, in)
|
||||
return
|
||||
}
|
||||
|
||||
// MaxSort 最大排序
|
||||
func (c *cTest) MaxSort(ctx context.Context, req *test.MaxSortReq) (res *test.MaxSortRes, err error) {
|
||||
data, err := service.AdminTest().MaxSort(ctx, adminin.TestMaxSortInp{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = new(test.MaxSortRes)
|
||||
res.TestMaxSortModel = data
|
||||
return
|
||||
}
|
||||
|
||||
// View 获取指定信息
|
||||
func (c *cTest) View(ctx context.Context, req *test.ViewReq) (res *test.ViewRes, err error) {
|
||||
var in adminin.TestViewInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := service.AdminTest().View(ctx, in)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = new(test.ViewRes)
|
||||
res.TestViewModel = data
|
||||
return
|
||||
}
|
||||
|
||||
// Delete 删除
|
||||
func (c *cTest) Delete(ctx context.Context, req *test.DeleteReq) (res *test.DeleteRes, err error) {
|
||||
var in adminin.TestDeleteInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = service.AdminTest().Delete(ctx, in)
|
||||
return
|
||||
}
|
||||
|
||||
// Status 更新状态
|
||||
func (c *cTest) Status(ctx context.Context, req *test.StatusReq) (res *test.StatusRes, err error) {
|
||||
var in adminin.TestStatusInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = service.AdminTest().Status(ctx, in)
|
||||
return
|
||||
}
|
||||
|
||||
// Switch 更新开关状态
|
||||
func (c *cTest) Switch(ctx context.Context, req *test.SwitchReq) (res *test.SwitchRes, err error) {
|
||||
var in adminin.TestSwitchInp
|
||||
if err = gconv.Scan(req, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = service.AdminTest().Switch(ctx, in)
|
||||
return
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package base
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package admin
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -17,8 +17,8 @@ import (
|
||||
"github.com/shirou/gopsutil/mem"
|
||||
"github.com/shirou/gopsutil/process"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/global"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/internal/websocket"
|
||||
"hotgo/utility/file"
|
||||
"hotgo/utility/format"
|
||||
@@ -51,6 +51,7 @@ type MonitorHead struct {
|
||||
func (c *cMonitor) RunInfo(client *websocket.Client, req *websocket.WRequest) {
|
||||
var (
|
||||
data = g.Map{}
|
||||
meta = service.AdminMonitor().GetMeta(client.Context())
|
||||
mHost, _ = host.Info()
|
||||
pwd, _ = os.Getwd()
|
||||
gm runtime.MemStats
|
||||
@@ -63,14 +64,14 @@ func (c *cMonitor) RunInfo(client *websocket.Client, req *websocket.WRequest) {
|
||||
"hostname": mHost.Hostname,
|
||||
"os": mHost.OS,
|
||||
"arch": mHost.KernelArch,
|
||||
"intranet_ip": global.MonitorData.IntranetIP,
|
||||
"public_ip": global.MonitorData.PublicIP,
|
||||
"intranet_ip": meta.IntranetIP,
|
||||
"public_ip": meta.PublicIP,
|
||||
|
||||
// GO运行信息
|
||||
"goName": "Golang",
|
||||
"version": runtime.Version(),
|
||||
"startTime": global.MonitorData.STartTime,
|
||||
"runTime": gtime.Now().Timestamp() - global.MonitorData.STartTime.Timestamp(),
|
||||
"startTime": meta.STartTime,
|
||||
"runTime": gtime.Now().Timestamp() - meta.STartTime.Timestamp(),
|
||||
"rootPath": runtime.GOROOT(),
|
||||
"pwd": pwd,
|
||||
"goroutine": runtime.NumGoroutine(),
|
||||
@@ -111,6 +112,7 @@ func (c *cMonitor) Trends(client *websocket.Client, req *websocket.WRequest) {
|
||||
data = g.Map{}
|
||||
monitorHeads []MonitorHead
|
||||
nets []NetC
|
||||
meta = service.AdminMonitor().GetMeta(client.Context())
|
||||
)
|
||||
|
||||
// cpu使用率
|
||||
@@ -123,8 +125,8 @@ func (c *cMonitor) Trends(client *websocket.Client, req *websocket.WRequest) {
|
||||
mMemUsed, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", mMem.UsedPercent), 64)
|
||||
|
||||
// 负载
|
||||
if len(global.MonitorData.LoadAvg) > 0 {
|
||||
mLoadAvg = global.MonitorData.LoadAvg[len(global.MonitorData.LoadAvg)-1]
|
||||
if len(meta.LoadAvg) > 0 {
|
||||
mLoadAvg = meta.LoadAvg[len(meta.LoadAvg)-1]
|
||||
}
|
||||
|
||||
monitorHeads = append(monitorHeads, MonitorHead{
|
||||
@@ -164,7 +166,7 @@ func (c *cMonitor) Trends(client *websocket.Client, req *websocket.WRequest) {
|
||||
IconClass: "Analytics",
|
||||
})
|
||||
|
||||
for _, v := range global.MonitorData.NetIO {
|
||||
for _, v := range meta.NetIO {
|
||||
nets = append(nets, NetC{
|
||||
Time: v.Time,
|
||||
BytesSent: format.FileSize(int64(v.BytesSent)), // 转换为最大整数单位
|
||||
@@ -176,7 +178,7 @@ func (c *cMonitor) Trends(client *websocket.Client, req *websocket.WRequest) {
|
||||
|
||||
data = g.Map{
|
||||
"head": monitorHeads,
|
||||
"load": global.MonitorData.LoadAvg,
|
||||
"load": meta.LoadAvg,
|
||||
"net": nets,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package common
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package websocket
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -8,7 +8,7 @@ package websocket
|
||||
|
||||
import (
|
||||
"context"
|
||||
"hotgo/internal/model/input/websocketin"
|
||||
"hotgo/api/websocket/base"
|
||||
"hotgo/internal/websocket"
|
||||
"hotgo/utility/simple"
|
||||
)
|
||||
@@ -18,8 +18,8 @@ var Send = send{}
|
||||
|
||||
type send struct{}
|
||||
|
||||
// ToTag 发送标签消息
|
||||
func (c *send) ToTag(ctx context.Context, req *websocketin.SendToTagReq) (res *websocketin.SendToTagRes, err error) {
|
||||
// SendToTag 发送标签消息
|
||||
func (c *send) SendToTag(ctx context.Context, req base.SendToTagReq) (res *base.SendToTagRes, err error) {
|
||||
simple.SafeGo(ctx, func(ctx context.Context) {
|
||||
websocket.SendToTag(req.Tag, &websocket.WResponse{
|
||||
Event: req.Response.Event,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package crons
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -72,7 +72,7 @@ func StartALL(sysCron []*entity.SysCron) error {
|
||||
)
|
||||
|
||||
if len(sysCron) == 0 {
|
||||
g.Log().Info(ct, "没有可用的定时任务")
|
||||
g.Log().Debug(ct, "no scheduled task is available.")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
// Package crons
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package crons
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/shirou/gopsutil/load"
|
||||
"github.com/shirou/gopsutil/net"
|
||||
"hotgo/internal/global"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/utility/format"
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cronList = append(cronList, Monitor)
|
||||
}
|
||||
|
||||
// Monitor 监控
|
||||
var Monitor = &cMonitor{name: "monitor"}
|
||||
|
||||
type cMonitor struct {
|
||||
name string
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func (c *cMonitor) GetName() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
// Execute 执行任务
|
||||
func (c *cMonitor) Execute(ctx context.Context) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
c.NetIO()
|
||||
c.loadAvg()
|
||||
}
|
||||
|
||||
func (c *cMonitor) loadAvg() {
|
||||
pl, _ := load.Avg()
|
||||
counter := model.LoadAvgStats{
|
||||
Time: gtime.Now(),
|
||||
Avg: pl.Load1,
|
||||
Ratio: pl.Load1 / (float64(runtime.NumCPU()) * 2) * 100,
|
||||
}
|
||||
|
||||
global.MonitorData.LoadAvg = append(global.MonitorData.LoadAvg, &counter)
|
||||
if len(global.MonitorData.LoadAvg) > 10 {
|
||||
global.MonitorData.LoadAvg = append(global.MonitorData.LoadAvg[:0], global.MonitorData.LoadAvg[(1):]...)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cMonitor) NetIO() {
|
||||
var counter model.NetIOCounters
|
||||
ni, _ := net.IOCounters(true)
|
||||
counter.Time = gtime.Now()
|
||||
for _, v := range ni {
|
||||
counter.BytesSent += v.BytesSent
|
||||
counter.BytesRecv += v.BytesRecv
|
||||
}
|
||||
|
||||
if len(global.MonitorData.NetIO) > 0 {
|
||||
lastNetIO := global.MonitorData.NetIO[len(global.MonitorData.NetIO)-1]
|
||||
sub := counter.Time.Sub(lastNetIO.Time).Seconds()
|
||||
counter.Down = format.Round2Float64((float64(counter.BytesRecv - lastNetIO.BytesRecv)) / sub)
|
||||
counter.UP = format.Round2Float64((float64(counter.BytesSent - lastNetIO.BytesSent)) / sub)
|
||||
}
|
||||
|
||||
global.MonitorData.NetIO = append(global.MonitorData.NetIO, &counter)
|
||||
if len(global.MonitorData.NetIO) > 10 {
|
||||
global.MonitorData.NetIO = append(global.MonitorData.NetIO[:0], global.MonitorData.NetIO[(1):]...)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package crons
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -16,7 +16,7 @@ func init() {
|
||||
cronList = append(cronList, Test)
|
||||
}
|
||||
|
||||
// Test 测试任务
|
||||
// Test 测试任务(无参数)
|
||||
var Test = &cTest{name: "test"}
|
||||
|
||||
type cTest struct {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package crons
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -17,7 +17,7 @@ func init() {
|
||||
cronList = append(cronList, Test2)
|
||||
}
|
||||
|
||||
// Test2 测试2任务
|
||||
// Test2 测试2任务(带参数)
|
||||
var Test2 = &cTest2{name: "test2"}
|
||||
|
||||
type cTest2 struct {
|
||||
|
||||
27
server/internal/dao/addon_hgexample_table.go
Normal file
27
server/internal/dao/addon_hgexample_table.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"hotgo/internal/dao/internal"
|
||||
)
|
||||
|
||||
// internalAddonHgexampleTableDao is internal type for wrapping internal DAO implements.
|
||||
type internalAddonHgexampleTableDao = *internal.AddonHgexampleTableDao
|
||||
|
||||
// addonHgexampleTableDao is the data access object for table hg_addon_hgexample_table.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type addonHgexampleTableDao struct {
|
||||
internalAddonHgexampleTableDao
|
||||
}
|
||||
|
||||
var (
|
||||
// AddonHgexampleTable is globally public accessible object for table hg_addon_hgexample_table operations.
|
||||
AddonHgexampleTable = addonHgexampleTableDao{
|
||||
internal.NewAddonHgexampleTableDao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Fill with you ideas below.
|
||||
@@ -11,15 +11,15 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// TestDao is the data access object for table hg_test.
|
||||
type TestDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns TestColumns // columns contains all the column names of Table for convenient usage.
|
||||
// AddonHgexampleTableDao is the data access object for table hg_addon_hgexample_table.
|
||||
type AddonHgexampleTableDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns AddonHgexampleTableColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// TestColumns defines and stores column names for table hg_test.
|
||||
type TestColumns struct {
|
||||
// AddonHgexampleTableColumns defines and stores column names for table hg_addon_hgexample_table.
|
||||
type AddonHgexampleTableColumns struct {
|
||||
Id string // ID
|
||||
CategoryId string // 分类ID
|
||||
Flag string // 标签
|
||||
@@ -59,8 +59,8 @@ type TestColumns struct {
|
||||
DeletedAt string // 删除时间
|
||||
}
|
||||
|
||||
// testColumns holds the columns for table hg_test.
|
||||
var testColumns = TestColumns{
|
||||
// addonHgexampleTableColumns holds the columns for table hg_addon_hgexample_table.
|
||||
var addonHgexampleTableColumns = AddonHgexampleTableColumns{
|
||||
Id: "id",
|
||||
CategoryId: "category_id",
|
||||
Flag: "flag",
|
||||
@@ -100,37 +100,37 @@ var testColumns = TestColumns{
|
||||
DeletedAt: "deleted_at",
|
||||
}
|
||||
|
||||
// NewTestDao creates and returns a new DAO object for table data access.
|
||||
func NewTestDao() *TestDao {
|
||||
return &TestDao{
|
||||
// NewAddonHgexampleTableDao creates and returns a new DAO object for table data access.
|
||||
func NewAddonHgexampleTableDao() *AddonHgexampleTableDao {
|
||||
return &AddonHgexampleTableDao{
|
||||
group: "default",
|
||||
table: "hg_test",
|
||||
columns: testColumns,
|
||||
table: "hg_addon_hgexample_table",
|
||||
columns: addonHgexampleTableColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *TestDao) DB() gdb.DB {
|
||||
func (dao *AddonHgexampleTableDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *TestDao) Table() string {
|
||||
func (dao *AddonHgexampleTableDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of current dao.
|
||||
func (dao *TestDao) Columns() TestColumns {
|
||||
func (dao *AddonHgexampleTableDao) Columns() AddonHgexampleTableColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *TestDao) Group() string {
|
||||
func (dao *AddonHgexampleTableDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *TestDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
func (dao *AddonHgexampleTableDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
@@ -140,6 +140,6 @@ func (dao *TestDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *TestDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
func (dao *AddonHgexampleTableDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
99
server/internal/dao/internal/sys_addons_config.go
Normal file
99
server/internal/dao/internal/sys_addons_config.go
Normal file
@@ -0,0 +1,99 @@
|
||||
// ==========================================================================
|
||||
// Code generated by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// SysAddonsConfigDao is the data access object for table hg_sys_addons_config.
|
||||
type SysAddonsConfigDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns SysAddonsConfigColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// SysAddonsConfigColumns defines and stores column names for table hg_sys_addons_config.
|
||||
type SysAddonsConfigColumns struct {
|
||||
Id string // 配置ID
|
||||
AddonName string // 插件名称
|
||||
Group string // 分组
|
||||
Name string // 参数名称
|
||||
Type string // 键值类型:string,int,uint,bool,datetime,date
|
||||
Key string // 参数键名
|
||||
Value string // 参数键值
|
||||
DefaultValue string // 默认值
|
||||
Sort string // 排序
|
||||
Tip string // 变量描述
|
||||
IsDefault string // 是否为系统默认
|
||||
Status string // 状态
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
}
|
||||
|
||||
// sysAddonsConfigColumns holds the columns for table hg_sys_addons_config.
|
||||
var sysAddonsConfigColumns = SysAddonsConfigColumns{
|
||||
Id: "id",
|
||||
AddonName: "addon_name",
|
||||
Group: "group",
|
||||
Name: "name",
|
||||
Type: "type",
|
||||
Key: "key",
|
||||
Value: "value",
|
||||
DefaultValue: "default_value",
|
||||
Sort: "sort",
|
||||
Tip: "tip",
|
||||
IsDefault: "is_default",
|
||||
Status: "status",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
}
|
||||
|
||||
// NewSysAddonsConfigDao creates and returns a new DAO object for table data access.
|
||||
func NewSysAddonsConfigDao() *SysAddonsConfigDao {
|
||||
return &SysAddonsConfigDao{
|
||||
group: "default",
|
||||
table: "hg_sys_addons_config",
|
||||
columns: sysAddonsConfigColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *SysAddonsConfigDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *SysAddonsConfigDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of current dao.
|
||||
func (dao *SysAddonsConfigDao) Columns() SysAddonsConfigColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *SysAddonsConfigDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *SysAddonsConfigDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *SysAddonsConfigDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
@@ -30,6 +30,7 @@ type SysGenCodesColumns struct {
|
||||
TableComment string // 主表注释
|
||||
DaoName string // 主表dao模型
|
||||
MasterColumns string // 主表字段
|
||||
AddonName string // 插件名称
|
||||
Status string // 生成状态
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
@@ -47,6 +48,7 @@ var sysGenCodesColumns = SysGenCodesColumns{
|
||||
TableComment: "table_comment",
|
||||
DaoName: "dao_name",
|
||||
MasterColumns: "master_columns",
|
||||
AddonName: "addon_name",
|
||||
Status: "status",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
|
||||
27
server/internal/dao/sys_addons_config.go
Normal file
27
server/internal/dao/sys_addons_config.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"hotgo/internal/dao/internal"
|
||||
)
|
||||
|
||||
// internalSysAddonsConfigDao is internal type for wrapping internal DAO implements.
|
||||
type internalSysAddonsConfigDao = *internal.SysAddonsConfigDao
|
||||
|
||||
// sysAddonsConfigDao is the data access object for table hg_sys_addons_config.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type sysAddonsConfigDao struct {
|
||||
internalSysAddonsConfigDao
|
||||
}
|
||||
|
||||
var (
|
||||
// SysAddonsConfig is globally public accessible object for table hg_sys_addons_config operations.
|
||||
SysAddonsConfig = sysAddonsConfigDao{
|
||||
internal.NewSysAddonsConfigDao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Fill with you ideas below.
|
||||
@@ -1,27 +0,0 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"hotgo/internal/dao/internal"
|
||||
)
|
||||
|
||||
// internalTestDao is internal type for wrapping internal DAO implements.
|
||||
type internalTestDao = *internal.TestDao
|
||||
|
||||
// testDao is the data access object for table hg_test.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type testDao struct {
|
||||
internalTestDao
|
||||
}
|
||||
|
||||
var (
|
||||
// Test is globally public accessible object for table hg_test operations.
|
||||
Test = testDao{
|
||||
internal.NewTestDao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Fill with you ideas below.
|
||||
@@ -1,13 +1,11 @@
|
||||
// Package global
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package global
|
||||
|
||||
import (
|
||||
"hotgo/internal/model"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
@@ -16,8 +14,6 @@ var (
|
||||
RootPtah string
|
||||
// SysType 操作系统类型 windows | linux
|
||||
SysType = runtime.GOOS
|
||||
// MonitorData 监控数据
|
||||
MonitorData model.MonitorData
|
||||
// Blacklists 黑名单列表
|
||||
Blacklists map[string]struct{}
|
||||
)
|
||||
@@ -1,9 +1,8 @@
|
||||
// Package global
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package global
|
||||
|
||||
import (
|
||||
@@ -12,20 +11,18 @@ import (
|
||||
"github.com/gogf/gf/v2"
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcache"
|
||||
"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"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/cache"
|
||||
"hotgo/internal/library/hggen"
|
||||
"hotgo/internal/library/location"
|
||||
"hotgo/internal/library/queue"
|
||||
"hotgo/internal/model/entity"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/utility/charset"
|
||||
"hotgo/utility/simple"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -38,47 +35,30 @@ func Init(ctx context.Context) {
|
||||
//g.SetDebug(debug.Bool())
|
||||
|
||||
// 默认上海时区
|
||||
if err := gtime.SetTimeZone("Asia/Shanghai"); err != nil {
|
||||
g.Log().Fatalf(ctx, "时区设置异常err:%+v", err)
|
||||
if err = gtime.SetTimeZone("Asia/Shanghai"); err != nil {
|
||||
g.Log().Fatalf(ctx, "时区设置异常 err:%+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
RootPtah, _ = os.Getwd()
|
||||
RootPtah = gfile.Pwd()
|
||||
fmt.Printf("欢迎使用HotGo!\r\n当前运行环境:%v, 运行根路径为:%v \r\nHotGo版本:v%v, gf版本:%v \n", SysType, RootPtah, consts.VersionApp, gf.VERSION)
|
||||
|
||||
setOrmCacheAdapter()
|
||||
|
||||
service.SysBlacklist().Load(ctx)
|
||||
// 设置缓存适配器
|
||||
cache.SetAdapter(ctx)
|
||||
|
||||
// 设置服务日志处理
|
||||
g.Log().SetHandlers(LoggingServeLogHandler)
|
||||
|
||||
startMonitor(ctx)
|
||||
// 启动服务监控
|
||||
service.AdminMonitor().StartMonitor(ctx)
|
||||
|
||||
// 加载ip访问黑名单
|
||||
service.SysBlacklist().Load(ctx)
|
||||
|
||||
// 初始化生成代码配置
|
||||
hggen.InIt(ctx)
|
||||
}
|
||||
|
||||
func startMonitor(ctx context.Context) {
|
||||
simple.SafeGo(ctx, func(ctx context.Context) {
|
||||
MonitorData.STartTime = gtime.Now()
|
||||
intranetIP, err := location.GetLocalIP()
|
||||
if err != nil {
|
||||
g.Log().Infof(ctx, "parse intranetIP err:%+v", err)
|
||||
}
|
||||
MonitorData.IntranetIP = intranetIP
|
||||
|
||||
publicIP, err := location.GetPublicIP(ctx)
|
||||
if err != nil {
|
||||
g.Log().Infof(ctx, "parse publicIP err:%+v", err)
|
||||
}
|
||||
MonitorData.PublicIP = publicIP
|
||||
})
|
||||
}
|
||||
|
||||
func setOrmCacheAdapter() {
|
||||
redisCache := gcache.NewAdapterRedis(g.Redis())
|
||||
g.DB().GetCache().SetAdapter(redisCache)
|
||||
}
|
||||
|
||||
func LoggingServeLogHandler(ctx context.Context, in *glog.HandlerInput) {
|
||||
in.Next(ctx)
|
||||
|
||||
@@ -89,6 +69,7 @@ func LoggingServeLogHandler(ctx context.Context, in *glog.HandlerInput) {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
conf, err := service.SysConfig().GetLoadServeLog(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
|
||||
38
server/internal/library/addons/addons.go
Normal file
38
server/internal/library/addons/addons.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// Package addons
|
||||
// @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 addons
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"hotgo/internal/consts"
|
||||
)
|
||||
|
||||
func GetTag(name string) string {
|
||||
return consts.AddonsTag + name
|
||||
}
|
||||
|
||||
func Tpl(name, tpl string) string {
|
||||
return consts.AddonsDir + "/" + name + "/" + tpl
|
||||
}
|
||||
|
||||
// RouterPrefix 路由前缀
|
||||
// 最终效果:/应用名称/插件模块名称/xxx/xxx。如果你不喜欢现在的路由风格,可以自行调整
|
||||
func RouterPrefix(ctx context.Context, app, name string) string {
|
||||
var prefix = "/"
|
||||
switch app {
|
||||
case consts.AppAdmin:
|
||||
prefix = g.Cfg().MustGet(ctx, "router.admin.prefix", "/admin").String()
|
||||
case consts.AppApi:
|
||||
prefix = g.Cfg().MustGet(ctx, "router.api.prefix", "/api").String()
|
||||
case consts.AppHome:
|
||||
prefix = g.Cfg().MustGet(ctx, "router.home.prefix", "/home").String()
|
||||
case consts.AppWebSocket:
|
||||
prefix = g.Cfg().MustGet(ctx, "router.ws.prefix", "/socket").String()
|
||||
}
|
||||
|
||||
return prefix + "/" + name
|
||||
}
|
||||
126
server/internal/library/addons/build.go
Normal file
126
server/internal/library/addons/build.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package addons
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Build 构建新插件
|
||||
func Build(ctx context.Context, sk Skeleton, conf *model.BuildAddonConfig) (err error) {
|
||||
buildPath := "./" + consts.AddonsDir + "/" + sk.Name
|
||||
modulesPath := "./" + consts.AddonsDir + "/modules/" + sk.Name + ".go"
|
||||
templatePath := gstr.Replace(conf.TemplatePath, "{$name}", sk.Name)
|
||||
replaces := map[string]string{
|
||||
"@{.label}": sk.Label,
|
||||
"@{.name}": sk.Name,
|
||||
"@{.group}": strconv.Itoa(sk.Group),
|
||||
"@{.brief}": sk.Brief,
|
||||
"@{.description}": sk.Description,
|
||||
"@{.author}": sk.Author,
|
||||
"@{.version}": sk.Version,
|
||||
}
|
||||
|
||||
if err = checkBuildDir(buildPath, modulesPath, templatePath); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// scans directory recursively
|
||||
list, err := gfile.ScanDirFunc(conf.SrcPath, "*", true, func(path string) string {
|
||||
return path
|
||||
})
|
||||
|
||||
for _, path := range list {
|
||||
if !gfile.IsReadable(path) {
|
||||
err = fmt.Errorf("file:%v is unreadable, please check permissions", path)
|
||||
return
|
||||
}
|
||||
|
||||
if gfile.IsDir(path) {
|
||||
continue
|
||||
}
|
||||
|
||||
flowFile := gstr.ReplaceByMap(path, map[string]string{
|
||||
gfile.RealPath(conf.SrcPath): "",
|
||||
".template": "",
|
||||
})
|
||||
|
||||
flowFile = buildPath + "/" + flowFile
|
||||
|
||||
content := gstr.ReplaceByMap(gfile.GetContents(path), replaces)
|
||||
|
||||
if err = gfile.PutContents(flowFile, content); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err = gfile.PutContents(templatePath+"/home/index.html", homeLayout); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = gfile.PutContents(modulesPath, gstr.ReplaceByMap(importModules, replaces))
|
||||
return
|
||||
}
|
||||
|
||||
func checkBuildDir(paths ...string) error {
|
||||
if len(paths) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, path := range paths {
|
||||
if gfile.Exists(path) {
|
||||
return fmt.Errorf("插件已存在,请换一个插件名称或者经确认无误后依次删除文件夹: [%v] 后重新生成", strings.Join(paths, "、\t"))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
importModules = `// Package modules
|
||||
// @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 modules
|
||||
|
||||
import _ "hotgo/addons/@{.name}"
|
||||
`
|
||||
|
||||
homeLayout = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no">
|
||||
<meta name="keywords" content="@{.Keywords}"/>
|
||||
<meta name="description" content="@{.Description}"/>
|
||||
<title>@{.Title}</title>
|
||||
<script type="text/javascript" src="/resource/home/js/jquery-3.6.0.min.js"></script>
|
||||
<style>
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="padding-top: 100px;text-align:center;">
|
||||
<h1><p>Hello,@{.Data.name}!!</p></h1>
|
||||
<h2><p>@{.Data.module}</p></h2>
|
||||
<h2><p>服务器时间:@{.Data.time}</p></h2>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<script>
|
||||
|
||||
</script>
|
||||
</html>`
|
||||
)
|
||||
142
server/internal/library/addons/install.go
Normal file
142
server/internal/library/addons/install.go
Normal file
@@ -0,0 +1,142 @@
|
||||
// Package addons
|
||||
// @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 addons
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"hotgo/internal/consts"
|
||||
)
|
||||
|
||||
// InstallRecord 安装记录
|
||||
type InstallRecord struct {
|
||||
Id int64 `json:"id" description:"安装ID"`
|
||||
Version string `json:"version" description:"安装版本"`
|
||||
Status int `json:"status" description:"安装状态"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"`
|
||||
}
|
||||
|
||||
func ScanInstall(m Module) (record *InstallRecord, err error) {
|
||||
err = g.Model("sys_addons_install").
|
||||
Ctx(m.Ctx()).
|
||||
Where("name", m.GetSkeleton().Name).
|
||||
Scan(&record)
|
||||
return
|
||||
}
|
||||
|
||||
// IsInstall 模块是否已安装
|
||||
func IsInstall(m Module) bool {
|
||||
record, err := ScanInstall(m)
|
||||
if err != nil {
|
||||
g.Log().Debugf(m.Ctx(), err.Error())
|
||||
return false
|
||||
}
|
||||
if record == nil {
|
||||
return false
|
||||
}
|
||||
return record.Status == consts.AddonsInstallStatusOk
|
||||
}
|
||||
|
||||
// Install 安装模块
|
||||
func Install(m Module) (err error) {
|
||||
record, err := ScanInstall(m)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if record != nil && record.Status == consts.AddonsInstallStatusOk {
|
||||
return gerror.New("插件已安装,无需重复操作!")
|
||||
}
|
||||
|
||||
data := g.Map{
|
||||
"name": m.GetSkeleton().Name,
|
||||
"version": m.GetSkeleton().Version,
|
||||
"status": consts.AddonsInstallStatusOk,
|
||||
}
|
||||
|
||||
return g.DB().Transaction(m.Ctx(), func(ctx context.Context, tx gdb.TX) error {
|
||||
if record != nil {
|
||||
_, err = g.Model("sys_addons_install").
|
||||
Ctx(m.Ctx()).
|
||||
Where("id", record.Id).
|
||||
Delete()
|
||||
}
|
||||
_, err = g.Model("sys_addons_install").
|
||||
Ctx(m.Ctx()).
|
||||
Data(data).
|
||||
Insert()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return m.Install(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
// Upgrade 更新模块
|
||||
func Upgrade(m Module) (err error) {
|
||||
record, err := ScanInstall(m)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if record == nil || record.Status != consts.AddonsInstallStatusOk {
|
||||
return gerror.New("插件未安装,请安装后操作!")
|
||||
}
|
||||
|
||||
data := g.Map{
|
||||
"version": m.GetSkeleton().Version,
|
||||
}
|
||||
|
||||
return g.DB().Transaction(m.Ctx(), func(ctx context.Context, tx gdb.TX) error {
|
||||
_, err = g.Model("sys_addons_install").
|
||||
Ctx(m.Ctx()).
|
||||
Where("id", record.Id).
|
||||
Data(data).
|
||||
Update()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return m.Upgrade(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
// UnInstall 卸载模块
|
||||
func UnInstall(m Module) (err error) {
|
||||
record, err := ScanInstall(m)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if record == nil || record.Status != consts.AddonsInstallStatusOk {
|
||||
return gerror.New("插件未安装,请安装后操作!")
|
||||
}
|
||||
|
||||
data := g.Map{
|
||||
"version": m.GetSkeleton().Version,
|
||||
"status": consts.AddonsInstallStatusUn,
|
||||
}
|
||||
|
||||
return g.DB().Transaction(m.Ctx(), func(ctx context.Context, tx gdb.TX) error {
|
||||
_, err = g.Model("sys_addons_install").
|
||||
Ctx(m.Ctx()).
|
||||
Where("id", record.Id).
|
||||
Data(data).
|
||||
Update()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return m.UnInstall(ctx)
|
||||
})
|
||||
}
|
||||
145
server/internal/library/addons/module.go
Normal file
145
server/internal/library/addons/module.go
Normal file
@@ -0,0 +1,145 @@
|
||||
// Package addons
|
||||
// @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 addons
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model/input/form"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Skeleton 模块骨架
|
||||
type Skeleton struct {
|
||||
Label string `json:"label"` // 标识
|
||||
Name string `json:"name"` // 名称
|
||||
Group int `json:"group"` // 分组
|
||||
Logo string `json:"logo"` // logo
|
||||
Brief string `json:"brief"` // 简介
|
||||
Description string `json:"description"` // 详细描述
|
||||
Author string `json:"author"` // 作者
|
||||
Version string `json:"version"` // 版本号
|
||||
RootPath string `json:"rootPath"` // 根路径
|
||||
}
|
||||
|
||||
func (s *Skeleton) GetModule() Module {
|
||||
return GetModule(s.Name)
|
||||
}
|
||||
|
||||
// Module 插件模块
|
||||
type Module interface {
|
||||
Init(ctx context.Context) // 初始化
|
||||
InitRouter(ctx context.Context, group *ghttp.RouterGroup) // 初始化并注册路由
|
||||
Ctx() context.Context // 上下文
|
||||
GetSkeleton() *Skeleton // 架子
|
||||
Install(ctx context.Context) error // 安装模块
|
||||
Upgrade(ctx context.Context) error // 更新模块
|
||||
UnInstall(ctx context.Context) error // 卸载模块
|
||||
}
|
||||
|
||||
var (
|
||||
modules = make(map[string]Module, 0)
|
||||
mLock sync.Mutex
|
||||
)
|
||||
|
||||
// InitModules 初始化所有已注册模块
|
||||
func InitModules(ctx context.Context) {
|
||||
for _, module := range modules {
|
||||
module.Init(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterModulesRouter 注册所有已安装模块路由
|
||||
func RegisterModulesRouter(ctx context.Context, group *ghttp.RouterGroup) {
|
||||
for _, module := range filterInstalled() {
|
||||
module.InitRouter(ctx, group)
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterModule 注册模块
|
||||
func RegisterModule(m Module) Module {
|
||||
mLock.Lock()
|
||||
defer mLock.Unlock()
|
||||
_, ok := modules[m.GetSkeleton().Name]
|
||||
if ok {
|
||||
panic("module repeat registration, name:" + m.GetSkeleton().Name)
|
||||
}
|
||||
modules[m.GetSkeleton().Name] = m
|
||||
return m
|
||||
}
|
||||
|
||||
// GetModule 获取指定名称模块
|
||||
func GetModule(name string) Module {
|
||||
mLock.Lock()
|
||||
defer mLock.Unlock()
|
||||
m, ok := modules[name]
|
||||
if !ok {
|
||||
panic("implement not found for interface " + name + ", forgot register?")
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// GetSkeletons 获取所有模块骨架
|
||||
func GetSkeletons() (list []*Skeleton) {
|
||||
var keys []string
|
||||
for k, _ := range modules {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, v := range keys {
|
||||
list = append(list, GetModule(v).GetSkeleton())
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// GetModuleRealPath 获取指定模块绝对路径
|
||||
func GetModuleRealPath(name string) string {
|
||||
path := gfile.RealPath(GetModulePath(name))
|
||||
if path == "" {
|
||||
panic("no path is found. please confirm that the path " + GetModulePath(name) + " exists?")
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// GetModulePath 获取指定模块相对路径
|
||||
func GetModulePath(name string) string {
|
||||
return "./" + consts.AddonsDir + "/" + name
|
||||
}
|
||||
|
||||
// filterInstalled 过滤已安装模块
|
||||
func filterInstalled() []Module {
|
||||
var ms []Module
|
||||
for _, module := range modules {
|
||||
if IsInstall(module) {
|
||||
ms = append(ms, module)
|
||||
}
|
||||
}
|
||||
return ms
|
||||
}
|
||||
|
||||
// ModuleSelect 获取插件模块选项
|
||||
func ModuleSelect() form.Selects {
|
||||
sks := GetSkeletons()
|
||||
lst := make(form.Selects, 0)
|
||||
if len(sks) == 0 {
|
||||
return lst
|
||||
}
|
||||
|
||||
for _, skeleton := range sks {
|
||||
lst = append(lst, &form.Select{
|
||||
Value: skeleton.Name,
|
||||
Label: skeleton.Label,
|
||||
Name: skeleton.Label,
|
||||
})
|
||||
}
|
||||
|
||||
return lst
|
||||
}
|
||||
68
server/internal/library/cache/cache.go
vendored
68
server/internal/library/cache/cache.go
vendored
@@ -1,24 +1,70 @@
|
||||
// Package cache
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcache"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"hotgo/internal/library/cache/file"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
|
||||
func New() *gcache.Cache {
|
||||
c := gcache.New()
|
||||
// cache 缓存驱动
|
||||
var cache *gcache.Cache
|
||||
|
||||
//redis
|
||||
adapter := gcache.NewAdapterRedis(g.Redis())
|
||||
|
||||
//内存
|
||||
//adapter := gcache.NewAdapterMemory()
|
||||
c.SetAdapter(adapter)
|
||||
return c
|
||||
// Instance 缓存实例
|
||||
func Instance() *gcache.Cache {
|
||||
if cache == nil {
|
||||
panic("cache uninitialized.")
|
||||
}
|
||||
return cache
|
||||
}
|
||||
|
||||
// SetAdapter 设置缓存适配器
|
||||
func SetAdapter(ctx context.Context) {
|
||||
var adapter gcache.Adapter
|
||||
conf, err := service.SysConfig().GetLoadCache(ctx)
|
||||
if err != nil {
|
||||
g.Log().Fatalf(ctx, "cache init err:%+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if conf == nil {
|
||||
conf = new(model.CacheConfig)
|
||||
g.Log().Infof(ctx, "no cache driver is configured. default memory cache is used.")
|
||||
}
|
||||
|
||||
switch conf.Adapter {
|
||||
case "redis":
|
||||
adapter = gcache.NewAdapterRedis(g.Redis())
|
||||
case "file":
|
||||
if conf.FileDir == "" {
|
||||
g.Log().Fatalf(ctx, "file path must be configured for file caching.")
|
||||
return
|
||||
}
|
||||
|
||||
if !gfile.Exists(conf.FileDir) {
|
||||
if err := gfile.Mkdir(conf.FileDir); err != nil {
|
||||
g.Log().Fatalf(ctx, "Failed to create the cache directory. Procedure, err:%+v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
adapter = file.NewAdapterFile(conf.FileDir)
|
||||
default:
|
||||
adapter = gcache.NewAdapterMemory()
|
||||
}
|
||||
|
||||
// 数据库缓存,默认和通用缓冲驱动一致,如果你不想使用默认的,可以自行调整
|
||||
g.DB().GetCache().SetAdapter(adapter)
|
||||
|
||||
// 通用缓存
|
||||
cache = gcache.New()
|
||||
cache.SetAdapter(adapter)
|
||||
return
|
||||
}
|
||||
|
||||
290
server/internal/library/cache/file/file.go
vendored
Normal file
290
server/internal/library/cache/file/file.go
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/container/gvar"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/os/gcache"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
// AdapterFile is the gcache adapter implements using file server.
|
||||
AdapterFile struct {
|
||||
dir string
|
||||
}
|
||||
|
||||
fileContent struct {
|
||||
Duration int64 `json:"duration"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
}
|
||||
)
|
||||
|
||||
const perm = 0o666
|
||||
|
||||
// NewAdapterFile creates and returns a new memory cache object.
|
||||
func NewAdapterFile(dir string) gcache.Adapter {
|
||||
return &AdapterFile{
|
||||
dir: dir,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *AdapterFile) Set(ctx context.Context, key interface{}, value interface{}, lifeTime time.Duration) (err error) {
|
||||
fileKey := gconv.String(key)
|
||||
if value == nil || lifeTime < 0 {
|
||||
return c.Delete(fileKey)
|
||||
}
|
||||
return c.Save(fileKey, gconv.String(value), lifeTime)
|
||||
}
|
||||
|
||||
func (c *AdapterFile) SetMap(ctx context.Context, data map[interface{}]interface{}, duration time.Duration) (err error) {
|
||||
return gerror.New("implement me")
|
||||
}
|
||||
|
||||
func (c *AdapterFile) SetIfNotExist(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (ok bool, err error) {
|
||||
return false, gerror.New("implement me")
|
||||
}
|
||||
|
||||
func (c *AdapterFile) SetIfNotExistFunc(ctx context.Context, key interface{}, f gcache.Func, duration time.Duration) (ok bool, err error) {
|
||||
return false, gerror.New("implement me")
|
||||
}
|
||||
|
||||
func (c *AdapterFile) SetIfNotExistFuncLock(ctx context.Context, key interface{}, f gcache.Func, duration time.Duration) (ok bool, err error) {
|
||||
return false, gerror.New("implement me")
|
||||
}
|
||||
|
||||
func (c *AdapterFile) Get(ctx context.Context, key interface{}) (*gvar.Var, error) {
|
||||
fetch, err := c.Fetch(gconv.String(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gvar.New(fetch), nil
|
||||
}
|
||||
|
||||
func (c *AdapterFile) GetOrSet(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (result *gvar.Var, err error) {
|
||||
return nil, gerror.New("implement me")
|
||||
}
|
||||
|
||||
func (c *AdapterFile) GetOrSetFunc(ctx context.Context, key interface{}, f gcache.Func, duration time.Duration) (result *gvar.Var, err error) {
|
||||
return nil, gerror.New("implement me")
|
||||
}
|
||||
|
||||
func (c *AdapterFile) GetOrSetFuncLock(ctx context.Context, key interface{}, f gcache.Func, duration time.Duration) (result *gvar.Var, err error) {
|
||||
return nil, gerror.New("implement me")
|
||||
}
|
||||
|
||||
func (c *AdapterFile) Contains(ctx context.Context, key interface{}) (bool, error) {
|
||||
return c.Has(gconv.String(key)), nil
|
||||
}
|
||||
|
||||
func (c *AdapterFile) Size(ctx context.Context) (size int, err error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (c *AdapterFile) Data(ctx context.Context) (data map[interface{}]interface{}, err error) {
|
||||
return nil, gerror.New("implement me")
|
||||
}
|
||||
|
||||
func (c *AdapterFile) Keys(ctx context.Context) (keys []interface{}, err error) {
|
||||
return nil, gerror.New("implement me")
|
||||
}
|
||||
|
||||
func (c *AdapterFile) Values(ctx context.Context) (values []interface{}, err error) {
|
||||
return nil, gerror.New("implement me")
|
||||
}
|
||||
|
||||
func (c *AdapterFile) Update(ctx context.Context, key interface{}, value interface{}) (oldValue *gvar.Var, exist bool, err error) {
|
||||
return nil, false, gerror.New("implement me")
|
||||
}
|
||||
|
||||
func (c *AdapterFile) UpdateExpire(ctx context.Context, key interface{}, duration time.Duration) (oldDuration time.Duration, err error) {
|
||||
var (
|
||||
v *gvar.Var
|
||||
oldTTL int64
|
||||
fileKey = gconv.String(key)
|
||||
)
|
||||
// TTL.
|
||||
expire, err := c.GetExpire(ctx, fileKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
oldTTL = int64(expire)
|
||||
if oldTTL == -2 {
|
||||
// It does not exist.
|
||||
oldTTL = -1
|
||||
return
|
||||
}
|
||||
oldDuration = time.Duration(oldTTL) * time.Second
|
||||
// DEL.
|
||||
if duration < 0 {
|
||||
err = c.Delete(fileKey)
|
||||
return
|
||||
}
|
||||
v, err = c.Get(ctx, fileKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = c.Set(ctx, fileKey, v.Val(), duration)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *AdapterFile) GetExpire(ctx context.Context, key interface{}) (time.Duration, error) {
|
||||
content, err := c.read(gconv.String(key))
|
||||
if err != nil {
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
if content.Duration <= time.Now().Unix() {
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
return time.Duration(time.Now().Unix()-content.Duration) * time.Second, nil
|
||||
}
|
||||
|
||||
func (c *AdapterFile) Remove(ctx context.Context, keys ...interface{}) (lastValue *gvar.Var, err error) {
|
||||
if len(keys) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
// Retrieves the last key value.
|
||||
if lastValue, err = c.Get(ctx, gconv.String(keys[len(keys)-1])); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Deletes all given keys.
|
||||
err = c.DeleteMulti(gconv.Strings(keys)...)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *AdapterFile) Clear(ctx context.Context) error {
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
func (c *AdapterFile) Close(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *AdapterFile) createName(key string) string {
|
||||
h := sha256.New()
|
||||
_, _ = h.Write([]byte(key))
|
||||
hash := hex.EncodeToString(h.Sum(nil))
|
||||
|
||||
return filepath.Join(c.dir, fmt.Sprintf("%s.cache", hash))
|
||||
}
|
||||
|
||||
func (c *AdapterFile) read(key string) (*fileContent, error) {
|
||||
value, err := ioutil.ReadFile(c.createName(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
content := &fileContent{}
|
||||
if err := json.Unmarshal(value, content); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if content.Duration == 0 {
|
||||
return content, nil
|
||||
}
|
||||
|
||||
if content.Duration <= time.Now().Unix() {
|
||||
_ = c.Delete(key)
|
||||
return nil, errors.New("cache expired")
|
||||
}
|
||||
|
||||
return content, nil
|
||||
}
|
||||
|
||||
// Has checks if the cached key exists into the File storage
|
||||
func (c *AdapterFile) Has(key string) bool {
|
||||
_, err := c.read(key)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// Delete the cached key from File storage
|
||||
func (c *AdapterFile) Delete(key string) error {
|
||||
_, err := os.Stat(c.createName(key))
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return os.Remove(c.createName(key))
|
||||
}
|
||||
|
||||
// DeleteMulti the cached key from File storage
|
||||
func (c *AdapterFile) DeleteMulti(keys ...string) (err error) {
|
||||
for _, key := range keys {
|
||||
if err = c.Delete(key); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch retrieves the cached value from key of the File storage
|
||||
func (c *AdapterFile) Fetch(key string) (interface{}, error) {
|
||||
content, err := c.read(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return content.Data, nil
|
||||
}
|
||||
|
||||
// FetchMulti retrieve multiple cached values from keys of the File storage
|
||||
func (c *AdapterFile) FetchMulti(keys []string) map[string]interface{} {
|
||||
result := make(map[string]interface{})
|
||||
for _, key := range keys {
|
||||
if value, err := c.Fetch(key); err == nil {
|
||||
result[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Flush removes all cached keys of the File storage
|
||||
func (c *AdapterFile) Flush() error {
|
||||
dir, err := os.Open(c.dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = dir.Close()
|
||||
}()
|
||||
|
||||
names, _ := dir.Readdirnames(-1)
|
||||
|
||||
for _, name := range names {
|
||||
_ = os.Remove(filepath.Join(c.dir, name))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Save a value in File storage by key
|
||||
func (c *AdapterFile) Save(key string, value string, lifeTime time.Duration) error {
|
||||
duration := int64(0)
|
||||
|
||||
if lifeTime > 0 {
|
||||
duration = time.Now().Unix() + int64(lifeTime.Seconds())
|
||||
}
|
||||
|
||||
content := &fileContent{duration, value}
|
||||
|
||||
data, err := json.Marshal(content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(c.createName(key), data, perm)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package captcha
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package casbin
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package casbin
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package casbin
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Package contexts
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package contexts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model"
|
||||
@@ -32,22 +32,42 @@ func Get(ctx context.Context) *model.Context {
|
||||
|
||||
// SetUser 将上下文信息设置到上下文请求中,注意是完整覆盖
|
||||
func SetUser(ctx context.Context, user *model.Identity) {
|
||||
Get(ctx).User = user
|
||||
c := Get(ctx)
|
||||
if c == nil {
|
||||
g.Log().Warningf(ctx, "contexts.SetUser, c == nil ")
|
||||
return
|
||||
}
|
||||
c.User = user
|
||||
}
|
||||
|
||||
// SetResponse 设置组件响应 用于访问日志使用
|
||||
func SetResponse(ctx context.Context, response *model.Response) {
|
||||
Get(ctx).Response = response
|
||||
c := Get(ctx)
|
||||
if c == nil {
|
||||
g.Log().Warningf(ctx, "contexts.SetResponse, c == nil ")
|
||||
return
|
||||
}
|
||||
c.Response = response
|
||||
}
|
||||
|
||||
// SetModule 设置应用模块
|
||||
func SetModule(ctx context.Context, module string) {
|
||||
Get(ctx).Module = module
|
||||
c := Get(ctx)
|
||||
if c == nil {
|
||||
g.Log().Warningf(ctx, "contexts.SetModule, c == nil ")
|
||||
return
|
||||
}
|
||||
c.Module = module
|
||||
}
|
||||
|
||||
// SetTakeUpTime 设置请求耗时
|
||||
func SetTakeUpTime(ctx context.Context, takeUpTime int64) {
|
||||
Get(ctx).TakeUpTime = takeUpTime
|
||||
c := Get(ctx)
|
||||
if c == nil {
|
||||
g.Log().Warningf(ctx, "contexts.SetTakeUpTime, c == nil ")
|
||||
return
|
||||
}
|
||||
c.TakeUpTime = takeUpTime
|
||||
}
|
||||
|
||||
// GetUser 获取用户信息
|
||||
@@ -62,30 +82,55 @@ func GetUser(ctx context.Context) *model.Identity {
|
||||
|
||||
// GetUserId 获取用户ID
|
||||
func GetUserId(ctx context.Context) int64 {
|
||||
user := Get(ctx).User
|
||||
user := GetUser(ctx)
|
||||
if user == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return user.Id
|
||||
}
|
||||
|
||||
// GetRoleId 获取用户角色ID
|
||||
func GetRoleId(ctx context.Context) int64 {
|
||||
user := Get(ctx).User
|
||||
user := GetUser(ctx)
|
||||
if user == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return user.RoleId
|
||||
}
|
||||
|
||||
// GetRoleKey 获取用户角色唯一编码
|
||||
func GetRoleKey(ctx context.Context) string {
|
||||
user := Get(ctx).User
|
||||
user := GetUser(ctx)
|
||||
if user == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return user.RoleKey
|
||||
}
|
||||
|
||||
// SetAddonName 设置插件信息
|
||||
func SetAddonName(ctx context.Context, name string) {
|
||||
c := Get(ctx)
|
||||
if c == nil {
|
||||
g.Log().Warningf(ctx, "contexts.SetAddonName, c == nil ")
|
||||
return
|
||||
}
|
||||
Get(ctx).AddonName = name
|
||||
}
|
||||
|
||||
// IsAddonRequest 是否为插件模块请求
|
||||
func IsAddonRequest(ctx context.Context) bool {
|
||||
c := Get(ctx)
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
return GetAddonName(ctx) != ""
|
||||
}
|
||||
|
||||
// GetAddonName 获取插件信息
|
||||
func GetAddonName(ctx context.Context) string {
|
||||
c := Get(ctx)
|
||||
if c == nil {
|
||||
return ""
|
||||
}
|
||||
return Get(ctx).AddonName
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package ems
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Package hggen
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package hggen
|
||||
|
||||
import (
|
||||
@@ -12,8 +11,10 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/addons"
|
||||
"hotgo/internal/library/hggen/internal/cmd"
|
||||
"hotgo/internal/library/hggen/internal/cmd/gendao"
|
||||
"hotgo/internal/library/hggen/internal/cmd/genservice"
|
||||
"hotgo/internal/library/hggen/views"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/internal/model/input/form"
|
||||
@@ -38,7 +39,16 @@ func Dao(ctx context.Context) (err error) {
|
||||
|
||||
// Service 生成业务接口
|
||||
func Service(ctx context.Context) (err error) {
|
||||
_, err = cmd.Gen.Service(ctx, GetServiceConfig())
|
||||
return ServiceWithCfg(ctx, GetServiceConfig())
|
||||
}
|
||||
|
||||
// ServiceWithCfg 生成业务接口
|
||||
func ServiceWithCfg(ctx context.Context, cfg ...genservice.CGenServiceInput) (err error) {
|
||||
c := GetServiceConfig()
|
||||
if len(cfg) > 0 {
|
||||
c = cfg[0]
|
||||
}
|
||||
_, err = cmd.Gen.Service(ctx, c)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -115,6 +125,8 @@ func TableSelects(ctx context.Context, in sysin.GenCodesSelectsInp) (res *sysin.
|
||||
})
|
||||
}
|
||||
|
||||
res.Addons = addons.ModuleSelect()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -125,7 +137,7 @@ func GenTypeSelect(ctx context.Context) (res sysin.GenTypeSelects, err error) {
|
||||
Value: k,
|
||||
Name: v,
|
||||
Label: v,
|
||||
Templates: make(form.Selects, 0),
|
||||
Templates: make(sysin.GenTemplateSelects, 0),
|
||||
}
|
||||
|
||||
confName, ok := consts.GenCodesTypeConfMap[k]
|
||||
@@ -137,10 +149,11 @@ func GenTypeSelect(ctx context.Context) (res sysin.GenTypeSelects, err error) {
|
||||
}
|
||||
if len(temps) > 0 {
|
||||
for index, temp := range temps {
|
||||
row.Templates = append(row.Templates, &form.Select{
|
||||
Value: index,
|
||||
Label: temp.Group,
|
||||
Name: temp.Group,
|
||||
row.Templates = append(row.Templates, &sysin.GenTemplateSelect{
|
||||
Value: index,
|
||||
Label: temp.Group,
|
||||
Name: temp.Group,
|
||||
IsAddon: temp.IsAddon,
|
||||
})
|
||||
}
|
||||
sort.Sort(row.Templates)
|
||||
@@ -207,14 +220,31 @@ func Build(ctx context.Context, in sysin.GenCodesBuildInp) (err error) {
|
||||
|
||||
switch in.GenType {
|
||||
case consts.GenCodesTypeCurd:
|
||||
pin := sysin.GenCodesPreviewInp(in)
|
||||
return views.Curd.DoBuild(ctx, &views.CurdBuildInput{
|
||||
PreviewIn: &views.CurdPreviewInput{
|
||||
In: sysin.GenCodesPreviewInp(in),
|
||||
In: pin,
|
||||
DaoConfig: GetDaoConfig(in.DbName),
|
||||
Config: genConfig,
|
||||
},
|
||||
BeforeEvent: views.CurdBuildEvent{"runDao": Dao},
|
||||
AfterEvent: views.CurdBuildEvent{"runService": Service},
|
||||
AfterEvent: views.CurdBuildEvent{"runService": func(ctx context.Context) (err error) {
|
||||
cfg := GetServiceConfig()
|
||||
if err = ServiceWithCfg(ctx, cfg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 插件模块,同时运行模块下的gen service
|
||||
if genConfig.Application.Crud.Templates[pin.GenTemplate].IsAddon {
|
||||
// 依然使用配置中的参数,只是将生成路径指向插件模块路径
|
||||
cfg.SrcFolder = "addons/" + pin.AddonName + "/logic"
|
||||
cfg.DstFolder = "addons/" + pin.AddonName + "/service"
|
||||
if err = ServiceWithCfg(ctx, cfg); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}},
|
||||
})
|
||||
case consts.GenCodesTypeTree:
|
||||
err = gerror.Newf("生成类型开发中!")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package hggen
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package views
|
||||
|
||||
import (
|
||||
@@ -70,6 +69,7 @@ type CurdOptions struct {
|
||||
Step *CurdStep // 转换后的流程控制条件
|
||||
dictMap g.Map // 字典选项 -> 字段映射关系
|
||||
TemplateGroup string `json:"templateGroup"`
|
||||
ApiPrefix string `json:"apiPrefix"`
|
||||
}
|
||||
|
||||
type CurdPreviewInput struct {
|
||||
@@ -123,7 +123,14 @@ func (l *gCurd) initInput(ctx context.Context, in *CurdPreviewInput) (err error)
|
||||
return gerror.New("没有找到生成模板的配置,请检查!")
|
||||
}
|
||||
|
||||
err = checkCurdPath(in.Config.Application.Crud.Templates[in.In.GenTemplate])
|
||||
// api前缀
|
||||
apiPrefix := gstr.LcFirst(in.In.VarName)
|
||||
if in.Config.Application.Crud.Templates[in.In.GenTemplate].IsAddon {
|
||||
apiPrefix = in.In.AddonName + "/" + apiPrefix
|
||||
}
|
||||
in.options.ApiPrefix = apiPrefix
|
||||
|
||||
err = checkCurdPath(in.Config.Application.Crud.Templates[in.In.GenTemplate], in.In.AddonName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -147,9 +154,10 @@ func initStep(ctx context.Context, in *CurdPreviewInput) {
|
||||
}
|
||||
|
||||
func (l *gCurd) loadView(ctx context.Context, in *CurdPreviewInput) (err error) {
|
||||
temp := in.Config.Application.Crud.Templates[in.In.GenTemplate]
|
||||
view := gview.New()
|
||||
err = view.SetConfigWithMap(g.Map{
|
||||
"Paths": in.Config.Application.Crud.Templates[in.In.GenTemplate].TemplatePath,
|
||||
"Paths": temp.TemplatePath,
|
||||
"Delimiters": in.Config.Delimiters,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -168,19 +176,48 @@ func (l *gCurd) loadView(ctx context.Context, in *CurdPreviewInput) (err error)
|
||||
return
|
||||
}
|
||||
|
||||
modName, err := GetModName(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
importApi := gstr.Replace(temp.ApiPath, "./", modName+"/") + "/" + strings.ToLower(in.In.VarName)
|
||||
importInput := gstr.Replace(temp.InputPath, "./", modName+"/")
|
||||
importController := gstr.Replace(temp.ControllerPath, "./", modName+"/")
|
||||
importService := "hotgo/internal/service"
|
||||
if temp.IsAddon {
|
||||
importService = "hotgo/addons/" + in.In.AddonName + "/service"
|
||||
}
|
||||
|
||||
importWebApi := "@/api/" + gstr.LcFirst(in.In.VarName)
|
||||
if temp.IsAddon {
|
||||
importWebApi = "@/api/addons/" + in.In.AddonName + "/" + gstr.LcFirst(in.In.VarName)
|
||||
}
|
||||
|
||||
componentPrefix := gstr.LcFirst(in.In.VarName)
|
||||
if temp.IsAddon {
|
||||
componentPrefix = "addons/" + in.In.AddonName + "/" + componentPrefix
|
||||
}
|
||||
|
||||
view.Assigns(gview.Params{
|
||||
"templateGroup": in.options.TemplateGroup, // 生成模板分组名称
|
||||
"servFunName": l.parseServFunName(in.options.TemplateGroup, in.In.VarName), // 业务服务名称
|
||||
"nowTime": gtime.Now().Format("Y-m-d H:i:s"), // 当前时间
|
||||
"version": runtime.Version(), // GO 版本
|
||||
"hgVersion": consts.VersionApp, // HG 版本
|
||||
"varName": in.In.VarName, // 实体名称
|
||||
"tableComment": in.In.TableComment, // 对外名称
|
||||
"daoName": in.In.DaoName, // ORM模型
|
||||
"masterFields": in.masterFields, // 主表字段
|
||||
"pk": in.pk, // 主键属性
|
||||
"options": in.options, // 提交选项
|
||||
"dictOptions": dictOptions, // web字典选项
|
||||
"templateGroup": in.options.TemplateGroup, // 生成模板分组名称
|
||||
"servFunName": l.parseServFunName(in.options.TemplateGroup, in.In.VarName), // 业务服务名称
|
||||
"nowTime": gtime.Now().Format("Y-m-d H:i:s"), // 当前时间
|
||||
"version": runtime.Version(), // GO 版本
|
||||
"hgVersion": consts.VersionApp, // HG 版本
|
||||
"varName": in.In.VarName, // 实体名称
|
||||
"tableComment": in.In.TableComment, // 对外名称
|
||||
"daoName": in.In.DaoName, // ORM模型
|
||||
"masterFields": in.masterFields, // 主表字段
|
||||
"pk": in.pk, // 主键属性
|
||||
"options": in.options, // 提交选项
|
||||
"dictOptions": dictOptions, // web字典选项
|
||||
"importApi": importApi, // 导入goApi包
|
||||
"importInput": importInput, // 导入input包
|
||||
"importController": importController, // 导入控制器包
|
||||
"importService": importService, // 导入业务服务
|
||||
"importWebApi": importWebApi, // 导入webApi
|
||||
"apiPrefix": in.options.ApiPrefix, // api前缀
|
||||
"componentPrefix": componentPrefix, // vue子组件前缀
|
||||
})
|
||||
in.view = view
|
||||
return
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package views
|
||||
|
||||
import (
|
||||
@@ -120,11 +119,19 @@ func (l *gCurd) generateWebEditScript(ctx context.Context, in *CurdPreviewInput)
|
||||
|
||||
if in.options.Step.HasMaxSort {
|
||||
importBuffer.WriteString(" import { onMounted, ref, computed, watch } from 'vue';\n")
|
||||
importBuffer.WriteString(" import { Edit, MaxSort, View } from '@/api/" + gstr.LcFirst(in.In.VarName) + "';\n")
|
||||
if in.Config.Application.Crud.Templates[in.In.GenTemplate].IsAddon {
|
||||
importBuffer.WriteString(" import { Edit, MaxSort, View } from '@/api/addons/" + in.In.AddonName + "/" + gstr.LcFirst(in.In.VarName) + "';\n")
|
||||
} else {
|
||||
importBuffer.WriteString(" import { Edit, MaxSort, View } from '@/api/" + gstr.LcFirst(in.In.VarName) + "';\n")
|
||||
}
|
||||
setupBuffer.WriteString(" function loadForm(value) {\n loading.value = true;\n\n // 新增\n if (value.id < 1) {\n params.value = newState(value);\n MaxSort()\n .then((res) => {\n params.value.sort = res.sort;\n })\n .finally(() => {\n loading.value = false;\n });\n return;\n }\n\n // 编辑\n View({ id: value.id })\n .then((res) => {\n params.value = res;\n })\n .finally(() => {\n loading.value = false;\n });\n }\n\n watch(\n () => props.formParams,\n (value) => {\n loadForm(value);\n }\n );")
|
||||
} else {
|
||||
importBuffer.WriteString(" import { onMounted, ref, computed } from 'vue';\n")
|
||||
importBuffer.WriteString(" import { Edit, View } from '@/api/" + gstr.LcFirst(in.In.VarName) + "';\n")
|
||||
if in.Config.Application.Crud.Templates[in.In.GenTemplate].IsAddon {
|
||||
importBuffer.WriteString(" import { Edit, View } from '@/api/addons/" + in.In.AddonName + "/" + gstr.LcFirst(in.In.VarName) + "';\n")
|
||||
} else {
|
||||
importBuffer.WriteString(" import { Edit, View } from '@/api/" + gstr.LcFirst(in.In.VarName) + "';\n")
|
||||
}
|
||||
setupBuffer.WriteString(" function loadForm(value) {\n // 新增\n if (value.id < 1) {\n params.value = newState(value);\n loading.value = false;\n return;\n }\n\n loading.value = true;\n // 编辑\n View({ id: value.id })\n .then((res) => {\n params.value = res;\n })\n .finally(() => {\n loading.value = false;\n });\n }\n\n watch(\n () => props.formParams,\n (value) => {\n loadForm(value);\n }\n );")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package views
|
||||
|
||||
import (
|
||||
@@ -14,8 +13,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
IndexApiImport = " import {%v } from '@/api/%s';"
|
||||
IndexIconsImport = " import {%v } from '@vicons/antd';"
|
||||
IndexApiImport = " import {%v } from '@/api/%s';" // 这里将导入的包路径写死了,后面可以优化成根据配置动态读取
|
||||
IndexApiAddonsImport = " import {%v } from '@/api/addons/%s/%s';"
|
||||
IndexIconsImport = " import {%v } from '@vicons/antd';"
|
||||
)
|
||||
|
||||
func (l *gCurd) webIndexTplData(ctx context.Context, in *CurdPreviewInput) (g.Map, error) {
|
||||
@@ -51,7 +51,11 @@ func (l *gCurd) webIndexTplData(ctx context.Context, in *CurdPreviewInput) (g.Ma
|
||||
apiImport = append(apiImport, " Status")
|
||||
}
|
||||
|
||||
data["apiImport"] = fmt.Sprintf(IndexApiImport, gstr.Implode(",", apiImport), gstr.LcFirst(in.In.VarName))
|
||||
if in.Config.Application.Crud.Templates[in.In.GenTemplate].IsAddon {
|
||||
data["apiImport"] = fmt.Sprintf(IndexApiAddonsImport, gstr.Implode(",", apiImport), in.In.AddonName, gstr.LcFirst(in.In.VarName))
|
||||
} else {
|
||||
data["apiImport"] = fmt.Sprintf(IndexApiImport, gstr.Implode(",", apiImport), gstr.LcFirst(in.In.VarName))
|
||||
}
|
||||
if len(iconsImport) > 0 {
|
||||
data["iconsImport"] = fmt.Sprintf(IndexIconsImport, gstr.Implode(",", iconsImport))
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package views
|
||||
|
||||
import (
|
||||
@@ -11,7 +10,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/utility/convert"
|
||||
)
|
||||
@@ -271,7 +269,7 @@ func (l *gCurd) generateWebModelColumnsEach(buffer *bytes.Buffer, in *CurdPrevie
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (isNullObject(row.%s)) {\n return ``;\n }\n return row.%s.map((attachfile) => {\n return h(\n %s,\n {\n size: 'small',\n style: {\n 'margin-left': '2px',\n },\n },\n {\n default: () => getFileExt(attachfile),\n }\n );\n });\n },\n },\n", field.Dc, field.TsName, field.TsName, field.TsName, "NAvatar")
|
||||
|
||||
case FormModeSwitch:
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n width: 100,\n render(row) {\n return h(%s, {\n value: row.%s === 1,\n checked: '开启',\n unchecked: '关闭',\n disabled: !hasPermission(['%s']),\n onUpdateValue: function (e) {\n console.log('onUpdateValue e:' + JSON.stringify(e));\n row.%s = e ? 1 : 2;\n Switch({ %s: row.%s, key: '%s', value: row.%s }).then((_res) => {\n $message.success('操作成功');\n });\n },\n });\n },\n },\n", field.Dc, field.TsName, "NSwitch", field.TsName, "/"+gstr.LcFirst(in.In.VarName)+"/switch", field.TsName, in.pk.TsName, in.pk.TsName, field.TsName, field.TsName)
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n width: 100,\n render(row) {\n return h(%s, {\n value: row.%s === 1,\n checked: '开启',\n unchecked: '关闭',\n disabled: !hasPermission(['%s']),\n onUpdateValue: function (e) {\n console.log('onUpdateValue e:' + JSON.stringify(e));\n row.%s = e ? 1 : 2;\n Switch({ %s: row.%s, key: '%s', value: row.%s }).then((_res) => {\n $message.success('操作成功');\n });\n },\n });\n },\n },\n", field.Dc, field.TsName, "NSwitch", field.TsName, "/"+in.options.ApiPrefix+"/switch", field.TsName, in.pk.TsName, in.pk.TsName, field.TsName, field.TsName)
|
||||
|
||||
case FormModeRate:
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n return h(%s, {\n allowHalf: true,\n readonly: true,\n defaultValue: row.%s,\n });\n },\n },\n", field.Dc, field.TsName, "NRate", field.TsName)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package views
|
||||
|
||||
import (
|
||||
@@ -11,6 +10,7 @@ import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model"
|
||||
@@ -98,40 +98,73 @@ func ImportSql(ctx context.Context, path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkCurdPath(temp *model.GenerateAppCrudTemplate) (err error) {
|
||||
func checkCurdPath(temp *model.GenerateAppCrudTemplate, addonName string) (err error) {
|
||||
if temp == nil {
|
||||
return gerror.New("生成模板配置不能为空")
|
||||
}
|
||||
|
||||
tip := `生成模板配置参数'%s'路径不存在,请先创建路径`
|
||||
if temp.IsAddon {
|
||||
temp.TemplatePath = gstr.Replace(temp.TemplatePath, "{$name}", addonName)
|
||||
temp.ApiPath = gstr.Replace(temp.ApiPath, "{$name}", addonName)
|
||||
temp.InputPath = gstr.Replace(temp.InputPath, "{$name}", addonName)
|
||||
temp.ControllerPath = gstr.Replace(temp.ControllerPath, "{$name}", addonName)
|
||||
temp.LogicPath = gstr.Replace(temp.LogicPath, "{$name}", addonName)
|
||||
temp.RouterPath = gstr.Replace(temp.RouterPath, "{$name}", addonName)
|
||||
temp.SqlPath = gstr.Replace(temp.SqlPath, "{$name}", addonName)
|
||||
temp.WebApiPath = gstr.Replace(temp.WebApiPath, "{$name}", addonName)
|
||||
temp.WebViewsPath = gstr.Replace(temp.WebViewsPath, "{$name}", addonName)
|
||||
}
|
||||
|
||||
tip := `生成模板配置参数'%s'路径不存在,请先创建路径:%s`
|
||||
|
||||
if !gfile.Exists(temp.TemplatePath) {
|
||||
return gerror.Newf(tip, "TemplatePath")
|
||||
return gerror.Newf(tip, "TemplatePath", temp.TemplatePath)
|
||||
}
|
||||
if !gfile.Exists(temp.ApiPath) {
|
||||
return gerror.Newf(tip, "ApiPath")
|
||||
return gerror.Newf(tip, "ApiPath", temp.ApiPath)
|
||||
}
|
||||
if !gfile.Exists(temp.InputPath) {
|
||||
return gerror.Newf(tip, "InputPath")
|
||||
return gerror.Newf(tip, "InputPath", temp.InputPath)
|
||||
}
|
||||
if !gfile.Exists(temp.ControllerPath) {
|
||||
return gerror.Newf(tip, "ControllerPath")
|
||||
return gerror.Newf(tip, "ControllerPath", temp.ControllerPath)
|
||||
}
|
||||
if !gfile.Exists(temp.LogicPath) {
|
||||
return gerror.Newf(tip, "LogicPath")
|
||||
return gerror.Newf(tip, "LogicPath", temp.LogicPath)
|
||||
}
|
||||
if !gfile.Exists(temp.RouterPath) {
|
||||
return gerror.Newf(tip, "RouterPath")
|
||||
return gerror.Newf(tip, "RouterPath", temp.RouterPath)
|
||||
}
|
||||
if !gfile.Exists(temp.SqlPath) {
|
||||
return gerror.Newf(tip, "SqlPath")
|
||||
return gerror.Newf(tip, "SqlPath", temp.SqlPath)
|
||||
}
|
||||
if !gfile.Exists(temp.WebApiPath) {
|
||||
return gerror.Newf(tip, "WebApiPath")
|
||||
return gerror.Newf(tip, "WebApiPath", temp.WebApiPath)
|
||||
}
|
||||
if !gfile.Exists(temp.WebViewsPath) {
|
||||
return gerror.Newf(tip, "WebViewsPath")
|
||||
return gerror.Newf(tip, "WebViewsPath", temp.WebViewsPath)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GetModName 获取主包名
|
||||
func GetModName(ctx context.Context) (modName string, err error) {
|
||||
if !gfile.Exists("go.mod") {
|
||||
err = gerror.New("go.mod does not exist in current working directory")
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
goModContent = gfile.GetContents("go.mod")
|
||||
match, _ = gregex.MatchString(`^module\s+(.+)\s*`, goModContent)
|
||||
)
|
||||
|
||||
if len(match) > 1 {
|
||||
modName = gstr.Trim(match[1])
|
||||
} else {
|
||||
err = gerror.New("module name does not found in go.mod")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package handler
|
||||
|
||||
import "github.com/gogf/gf/v2/database/gdb"
|
||||
import (
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
)
|
||||
|
||||
// ForceCache 强制缓存
|
||||
func ForceCache(m *gdb.Model) *gdb.Model {
|
||||
return m.Cache(gdb.CacheOption{Duration: -1, Force: true})
|
||||
return m.Cache(gdb.CacheOption{Duration: 0, Force: true})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package handler
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Package jwt
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package jwt
|
||||
|
||||
import (
|
||||
@@ -54,18 +53,17 @@ func GenerateLoginToken(ctx context.Context, user *model.Identity, isRefresh boo
|
||||
var (
|
||||
tokenStringMd5 = gmd5.MustEncryptString(tokenString)
|
||||
// 绑定登录token
|
||||
c = cache.New()
|
||||
key = consts.RedisJwtToken + tokenStringMd5
|
||||
key = consts.CacheJwtToken + tokenStringMd5
|
||||
// 将有效期转为持续时间,单位:秒
|
||||
expires, _ = time.ParseDuration(fmt.Sprintf("+%vs", user.Expires))
|
||||
)
|
||||
|
||||
err = c.Set(ctx, key, tokenString, expires)
|
||||
err = cache.Instance().Set(ctx, key, tokenString, expires)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = c.Set(ctx, consts.RedisJwtUserBind+user.App+":"+gconv.String(user.Id), key, expires)
|
||||
err = cache.Instance().Set(ctx, consts.CacheJwtUserBind+user.App+":"+gconv.String(user.Id), key, expires)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package location
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
@@ -198,11 +198,11 @@ func GetClientIp(r *ghttp.Request) string {
|
||||
|
||||
// 如果存在多个,默认取第一个
|
||||
if gstr.Contains(ip, ",") {
|
||||
ip = gstr.TrimStr(ip, ",", -1)
|
||||
ip = gstr.StrTillEx(ip, ",")
|
||||
}
|
||||
|
||||
if gstr.Contains(ip, ", ") {
|
||||
ip = gstr.TrimStr(ip, ", ", -1)
|
||||
ip = gstr.StrTillEx(ip, ", ")
|
||||
}
|
||||
|
||||
return ip
|
||||
|
||||
137
server/internal/library/queue/disk.go
Normal file
137
server/internal/library/queue/disk.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package queue
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"hotgo/internal/library/queue/disk"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DiskProducerMq struct {
|
||||
config *disk.Config
|
||||
producers map[string]*disk.Queue
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
type DiskConsumerMq struct {
|
||||
config *disk.Config
|
||||
}
|
||||
|
||||
func RegisterDiskMqConsumer(config *disk.Config) (client MqConsumer, err error) {
|
||||
return &DiskConsumerMq{
|
||||
config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ListenReceiveMsgDo 消费数据
|
||||
func (q *DiskConsumerMq) ListenReceiveMsgDo(topic string, receiveDo func(mqMsg MqMsg)) (err error) {
|
||||
if topic == "" {
|
||||
return gerror.New("disk.ListenReceiveMsgDo topic is empty")
|
||||
}
|
||||
|
||||
var (
|
||||
queue = NewDiskQueue(topic, q.config)
|
||||
sleep = time.Second
|
||||
)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
if index, offset, data, err := queue.Read(); err == nil {
|
||||
var mqMsg MqMsg
|
||||
if err = json.Unmarshal(data, &mqMsg); err != nil {
|
||||
g.Log().Warningf(ctx, "disk.ListenReceiveMsgDo Unmarshal err:%+v, topic:%v, data:%+v .", err, topic, string(data))
|
||||
continue
|
||||
}
|
||||
if mqMsg.MsgId != "" {
|
||||
receiveDo(mqMsg)
|
||||
queue.Commit(index, offset)
|
||||
sleep = time.Millisecond * 1
|
||||
}
|
||||
} else {
|
||||
sleep = time.Second
|
||||
}
|
||||
|
||||
time.Sleep(sleep)
|
||||
}
|
||||
}()
|
||||
|
||||
select {}
|
||||
}
|
||||
|
||||
func RegisterDiskMqProducer(config *disk.Config) (client MqProducer, err error) {
|
||||
return &DiskProducerMq{
|
||||
config: config,
|
||||
producers: make(map[string]*disk.Queue),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SendMsg 按字符串类型生产数据
|
||||
func (d *DiskProducerMq) SendMsg(topic string, body string) (mqMsg MqMsg, err error) {
|
||||
return d.SendByteMsg(topic, []byte(body))
|
||||
}
|
||||
|
||||
// SendByteMsg 生产数据
|
||||
func (d *DiskProducerMq) SendByteMsg(topic string, body []byte) (mqMsg MqMsg, err error) {
|
||||
if topic == "" {
|
||||
return mqMsg, gerror.New("DiskMq topic is empty")
|
||||
}
|
||||
|
||||
mqMsg = MqMsg{
|
||||
RunType: SendMsg,
|
||||
Topic: topic,
|
||||
MsgId: getRandMsgId(),
|
||||
Body: body,
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
|
||||
mqMsgJson, err := json.Marshal(mqMsg)
|
||||
if err != nil {
|
||||
return mqMsg, gerror.New(fmt.Sprint("queue redis 生产者解析json消息失败:", err))
|
||||
}
|
||||
|
||||
queue := d.getProducer(topic)
|
||||
if err = queue.Write(mqMsgJson); err != nil {
|
||||
return mqMsg, gerror.New(fmt.Sprint("queue disk 生产者添加消息失败:", err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *DiskProducerMq) getProducer(topic string) *disk.Queue {
|
||||
queue, ok := d.producers[topic]
|
||||
if ok {
|
||||
return queue
|
||||
}
|
||||
queue = NewDiskQueue(topic, d.config)
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
d.producers[topic] = queue
|
||||
return queue
|
||||
}
|
||||
|
||||
func NewDiskQueue(topic string, config *disk.Config) *disk.Queue {
|
||||
conf := &disk.Config{
|
||||
Path: fmt.Sprintf(config.Path + "/" + config.GroupName + "/" + topic),
|
||||
BatchSize: config.BatchSize,
|
||||
BatchTime: config.BatchTime * time.Second,
|
||||
SegmentSize: config.SegmentSize,
|
||||
SegmentLimit: config.SegmentLimit,
|
||||
}
|
||||
|
||||
if !gfile.Exists(conf.Path) {
|
||||
if err := gfile.Mkdir(conf.Path); err != nil {
|
||||
g.Log().Errorf(ctx, "NewDiskQueue Failed to create the cache directory. Procedure, err:%+v", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
queue, err := disk.New(conf)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "NewDiskQueue err:%v", err)
|
||||
return nil
|
||||
}
|
||||
return queue
|
||||
}
|
||||
118
server/internal/library/queue/disk/disk.go
Normal file
118
server/internal/library/queue/disk/disk.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
filePerm = 0600 // 数据写入权限
|
||||
indexFile = ".index" // 消息索引文件
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
GroupName string // 组群名称
|
||||
Path string // 数据存放路径
|
||||
BatchSize int64 // 每N条消息同步一次,batchSize和batchTime满足其一就会同步一次
|
||||
BatchTime time.Duration // 每N秒消息同步一次
|
||||
SegmentSize int64 // 每个topic分片数据文件最大字节
|
||||
SegmentLimit int64 // 每个topic最大分片数据文件数量
|
||||
}
|
||||
|
||||
type Queue struct {
|
||||
sync.RWMutex
|
||||
close bool
|
||||
ticker *time.Ticker
|
||||
wg *sync.WaitGroup
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
writer *writer
|
||||
reader *reader
|
||||
}
|
||||
|
||||
func New(config *Config) (queue *Queue, err error) {
|
||||
if _, err = os.Stat(config.Path); err != nil {
|
||||
return
|
||||
}
|
||||
queue = &Queue{close: false, wg: &sync.WaitGroup{}, writer: &writer{config: config}, reader: &reader{config: config}}
|
||||
queue.ticker = time.NewTicker(config.BatchTime)
|
||||
queue.ctx, queue.cancel = context.WithCancel(context.TODO())
|
||||
err = queue.reader.restore()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go queue.sync()
|
||||
return
|
||||
}
|
||||
|
||||
// Write data
|
||||
func (q *Queue) Write(data []byte) error {
|
||||
if q.close {
|
||||
return errors.New("closed")
|
||||
}
|
||||
|
||||
q.Lock()
|
||||
defer q.Unlock()
|
||||
|
||||
return q.writer.write(data)
|
||||
}
|
||||
|
||||
// Read data
|
||||
func (q *Queue) Read() (int64, int64, []byte, error) {
|
||||
if q.close {
|
||||
return 0, 0, nil, errors.New("closed")
|
||||
}
|
||||
|
||||
q.RLock()
|
||||
defer q.RUnlock()
|
||||
|
||||
index, offset, data, err := q.reader.read()
|
||||
if err == io.EOF && (q.writer.file == nil || q.reader.file.Name() != q.writer.file.Name()) {
|
||||
_ = q.reader.safeRotate()
|
||||
}
|
||||
return index, offset, data, err
|
||||
}
|
||||
|
||||
// Commit index and offset
|
||||
func (q *Queue) Commit(index int64, offset int64) {
|
||||
if q.close {
|
||||
return
|
||||
}
|
||||
|
||||
ck := &q.reader.checkpoint
|
||||
ck.Index, ck.Offset = index, offset
|
||||
q.reader.sync()
|
||||
}
|
||||
|
||||
// Close Queue
|
||||
func (q *Queue) Close() {
|
||||
if q.close {
|
||||
return
|
||||
}
|
||||
|
||||
q.close = true
|
||||
q.cancel()
|
||||
q.wg.Wait()
|
||||
q.writer.close()
|
||||
q.reader.close()
|
||||
}
|
||||
|
||||
// sync data
|
||||
func (q *Queue) sync() {
|
||||
q.wg.Add(1)
|
||||
defer q.wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-q.ticker.C:
|
||||
q.Lock()
|
||||
q.writer.sync()
|
||||
q.Unlock()
|
||||
case <-q.ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
176
server/internal/library/queue/disk/reader.go
Normal file
176
server/internal/library/queue/disk/reader.go
Normal file
@@ -0,0 +1,176 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
errorQueueEmpty = errors.New("queue is empty")
|
||||
)
|
||||
|
||||
type reader struct {
|
||||
file *os.File
|
||||
index int64
|
||||
offset int64
|
||||
reader *bufio.Reader
|
||||
checkpoint checkpoint
|
||||
config *Config
|
||||
}
|
||||
|
||||
type checkpoint struct {
|
||||
Index int64 `json:"index"`
|
||||
Offset int64 `json:"offset"`
|
||||
}
|
||||
|
||||
// read data
|
||||
func (r *reader) read() (int64, int64, []byte, error) {
|
||||
if err := r.check(); err != nil {
|
||||
return r.index, r.offset, nil, err
|
||||
}
|
||||
|
||||
// read a line
|
||||
data, err := r.reader.ReadBytes('\n')
|
||||
if err != nil {
|
||||
return r.index, r.offset, nil, err
|
||||
}
|
||||
data = bytes.TrimRight(data, "\n")
|
||||
|
||||
r.offset += int64(len(data)) + 1
|
||||
return r.index, r.offset, data, err
|
||||
}
|
||||
|
||||
// check a new segment
|
||||
func (r *reader) check() error {
|
||||
if r.file != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
file, err := r.next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return r.open(file)
|
||||
}
|
||||
|
||||
func (r *reader) open(file string) (err error) {
|
||||
if r.file, err = os.OpenFile(file, os.O_RDONLY, filePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get file index
|
||||
r.index = r.getIndex(file)
|
||||
|
||||
// seek read offset
|
||||
if _, err = r.file.Seek(r.offset, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.reader = bufio.NewReader(r.file)
|
||||
return nil
|
||||
}
|
||||
|
||||
// safeRotate to next segment
|
||||
func (r *reader) safeRotate() error {
|
||||
// if there is no next file, it is not cleared
|
||||
if _, err := r.next(); err == errorQueueEmpty {
|
||||
return nil
|
||||
}
|
||||
|
||||
return r.rotate()
|
||||
}
|
||||
|
||||
// rotate to next segment
|
||||
func (r *reader) rotate() error {
|
||||
if r.file == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// close segment
|
||||
_ = r.file.Close()
|
||||
r.file, r.offset, r.reader = nil, 0, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// close reader
|
||||
func (r *reader) close() {
|
||||
if r.file == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := r.file.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
r.file, r.reader, r.index, r.offset = nil, nil, 0, 0
|
||||
}
|
||||
|
||||
// sync index and offset
|
||||
func (r *reader) sync() {
|
||||
name := path.Join(r.config.Path, indexFile)
|
||||
data, _ := json.Marshal(&r.checkpoint)
|
||||
_ = ioutil.WriteFile(name, data, filePerm)
|
||||
}
|
||||
|
||||
// restore index and offset
|
||||
func (r *reader) restore() (err error) {
|
||||
name := path.Join(r.config.Path, indexFile)
|
||||
|
||||
// uninitialized
|
||||
if _, err1 := os.Stat(name); err1 != nil {
|
||||
r.sync()
|
||||
}
|
||||
|
||||
data, _ := ioutil.ReadFile(name)
|
||||
|
||||
_ = json.Unmarshal(data, &r.checkpoint)
|
||||
r.index, r.offset = r.checkpoint.Index, r.checkpoint.Offset
|
||||
if r.index == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if err = r.open(fmt.Sprintf("%s/%d.data", r.config.Path, r.index)); err != nil {
|
||||
r.offset = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// next segment
|
||||
func (r *reader) next() (string, error) {
|
||||
files, err := filepath.Glob(filepath.Join(r.config.Path, "*.data"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sort.Strings(files)
|
||||
|
||||
for _, file := range files {
|
||||
index := r.getIndex(file)
|
||||
if index < r.checkpoint.Index {
|
||||
_ = os.Remove(file) // remove expired segment
|
||||
}
|
||||
|
||||
if index > r.index {
|
||||
return file, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", errorQueueEmpty
|
||||
}
|
||||
|
||||
// get segment index
|
||||
func (r *reader) getIndex(filename string) int64 {
|
||||
base := filepath.Base(filename)
|
||||
name := base[0 : len(base)-len(path.Ext(filename))]
|
||||
index, _ := strconv.ParseInt(name, 10, 64)
|
||||
return index
|
||||
}
|
||||
102
server/internal/library/queue/disk/writer.go
Normal file
102
server/internal/library/queue/disk/writer.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
type writer struct {
|
||||
file *os.File
|
||||
size int64
|
||||
count int64
|
||||
writer *bufio.Writer
|
||||
config *Config
|
||||
}
|
||||
|
||||
// write data
|
||||
func (w *writer) write(data []byte) error {
|
||||
// append newline
|
||||
data = append(data, "\n"...)
|
||||
size := int64(len(data))
|
||||
|
||||
// close current segment for rotate
|
||||
if w.size+size > w.config.SegmentSize {
|
||||
w.close()
|
||||
}
|
||||
|
||||
// create a new segment
|
||||
if w.file == nil {
|
||||
if err := w.open(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// write to buffer
|
||||
if _, err := w.writer.Write(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.size += size
|
||||
|
||||
// sync data to disk
|
||||
w.count++
|
||||
if w.count >= w.config.BatchSize {
|
||||
w.sync()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// create a new segment
|
||||
func (w *writer) open() (err error) {
|
||||
if w.segmentNum() >= w.config.SegmentLimit {
|
||||
return errors.New("segment num exceeds the limit")
|
||||
}
|
||||
|
||||
name := path.Join(w.config.Path, fmt.Sprintf("%013d.data", time.Now().UnixNano()/1e6))
|
||||
if w.file, err = os.OpenFile(name, os.O_CREATE|os.O_WRONLY, filePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.size = 0
|
||||
// disable auto flush
|
||||
w.writer = bufio.NewWriterSize(w.file, int(w.config.SegmentSize))
|
||||
w.writer.Reset(w.file)
|
||||
return err
|
||||
}
|
||||
|
||||
// sync data to disk
|
||||
func (w *writer) sync() {
|
||||
if w.writer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := w.writer.Flush(); err == nil {
|
||||
w.count = 0
|
||||
}
|
||||
}
|
||||
|
||||
// close segment
|
||||
func (w *writer) close() {
|
||||
if w.file == nil {
|
||||
return
|
||||
}
|
||||
|
||||
w.sync()
|
||||
if err := w.file.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
w.size, w.file, w.writer = 0, nil, nil
|
||||
}
|
||||
|
||||
// segment num
|
||||
func (w *writer) segmentNum() int64 {
|
||||
segments, _ := filepath.Glob(path.Join(w.config.Path, "*.data"))
|
||||
return int64(len(segments))
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
// Package queue
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package queue
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"hotgo/internal/library/queue/disk"
|
||||
"hotgo/utility/charset"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -31,21 +31,21 @@ const (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Switch bool `json:"switch"`
|
||||
Driver string `json:"driver"`
|
||||
Retry int `json:"retry"`
|
||||
MultiComsumer bool `json:"multiComsumer"`
|
||||
GroupName string `json:"groupName"`
|
||||
Redis RedisConf
|
||||
Rocketmq RocketmqConf
|
||||
Kafka KafkaConf
|
||||
Switch bool `json:"switch"`
|
||||
Driver string `json:"driver"`
|
||||
Retry int `json:"retry"`
|
||||
GroupName string `json:"groupName"`
|
||||
Redis RedisConf
|
||||
Rocketmq RocketmqConf
|
||||
Kafka KafkaConf
|
||||
Disk *disk.Config
|
||||
}
|
||||
|
||||
type RedisConf struct {
|
||||
Address string `json:"address"`
|
||||
Db int `json:"db"`
|
||||
Pass string `json:"pass"`
|
||||
Timeout int `json:"timeout"`
|
||||
Address string `json:"address"`
|
||||
Db int `json:"db"`
|
||||
Pass string `json:"pass"`
|
||||
IdleTimeout int `json:"idleTimeout"`
|
||||
}
|
||||
type RocketmqConf struct {
|
||||
Address []string `json:"address"`
|
||||
@@ -53,9 +53,10 @@ type RocketmqConf struct {
|
||||
}
|
||||
|
||||
type KafkaConf struct {
|
||||
Address []string `json:"address"`
|
||||
Version string `json:"version"`
|
||||
RandClient bool `json:"randClient"`
|
||||
Address []string `json:"address"`
|
||||
Version string `json:"version"`
|
||||
RandClient bool `json:"randClient"`
|
||||
MultiConsumer bool `json:"multiConsumer"`
|
||||
}
|
||||
|
||||
type MqMsg struct {
|
||||
@@ -80,7 +81,7 @@ func init() {
|
||||
mqProducerInstanceMap = make(map[string]MqProducer)
|
||||
mqConsumerInstanceMap = make(map[string]MqConsumer)
|
||||
if err := g.Cfg().MustGet(ctx, "queue").Scan(&config); err != nil {
|
||||
g.Log().Infof(ctx, "queue init err:%+v", err)
|
||||
g.Log().Warning(ctx, "queue init err:%+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,11 +133,13 @@ func NewProducer(groupName string) (mqClient MqProducer, err error) {
|
||||
Addr: config.Redis.Address,
|
||||
Passwd: config.Redis.Pass,
|
||||
DBnum: config.Redis.Db,
|
||||
Timeout: config.Redis.Timeout,
|
||||
Timeout: config.Redis.IdleTimeout,
|
||||
}, PoolOption{
|
||||
5, 50, 5,
|
||||
}, groupName, config.Retry)
|
||||
|
||||
case "disk":
|
||||
config.Disk.GroupName = groupName
|
||||
mqClient, err = RegisterDiskMqProducer(config.Disk)
|
||||
default:
|
||||
err = gerror.New("queue driver is not support")
|
||||
}
|
||||
@@ -154,17 +157,6 @@ func NewProducer(groupName string) (mqClient MqProducer, err error) {
|
||||
|
||||
// NewConsumer 初始化消费者实例
|
||||
func NewConsumer(groupName string) (mqClient MqConsumer, err error) {
|
||||
randTag := string(charset.RandomCreateBytes(6))
|
||||
|
||||
// 是否支持创建多个消费者
|
||||
if config.MultiComsumer == false {
|
||||
randTag = "001"
|
||||
}
|
||||
|
||||
if item, ok := mqConsumerInstanceMap[groupName+"-"+randTag]; ok {
|
||||
return item, nil
|
||||
}
|
||||
|
||||
if groupName == "" {
|
||||
err = gerror.New("mq groupName is empty.")
|
||||
return
|
||||
@@ -183,6 +175,16 @@ func NewConsumer(groupName string) (mqClient MqConsumer, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
randTag := string(charset.RandomCreateBytes(6))
|
||||
// 是否支持创建多个消费者
|
||||
if config.Kafka.MultiConsumer == false {
|
||||
randTag = "001"
|
||||
}
|
||||
|
||||
if item, ok := mqConsumerInstanceMap[groupName+"-"+randTag]; ok {
|
||||
return item, nil
|
||||
}
|
||||
|
||||
clientId := "HOTGO-Consumer-" + groupName
|
||||
if config.Kafka.RandClient {
|
||||
clientId += "-" + randTag
|
||||
@@ -204,10 +206,13 @@ func NewConsumer(groupName string) (mqClient MqConsumer, err error) {
|
||||
Addr: config.Redis.Address,
|
||||
Passwd: config.Redis.Pass,
|
||||
DBnum: config.Redis.Db,
|
||||
Timeout: config.Redis.Timeout,
|
||||
Timeout: config.Redis.IdleTimeout,
|
||||
}, PoolOption{
|
||||
5, 50, 5,
|
||||
}, groupName)
|
||||
case "disk":
|
||||
config.Disk.GroupName = groupName
|
||||
mqClient, err = RegisterDiskMqConsumer(config.Disk)
|
||||
default:
|
||||
err = gerror.New("queue driver is not support")
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user