This commit is contained in:
孟帅
2023-02-23 17:53:04 +08:00
parent 7cf1b8ce8e
commit 61d0988d2c
402 changed files with 18340 additions and 35547 deletions

View File

@@ -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
`,
}

View File

@@ -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
//

View File

@@ -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)
})
// 启动定时任务

View File

@@ -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
//

View File

@@ -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
//

View 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: "已卸载",
}

View File

@@ -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"
)

View File

@@ -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-用户身份绑定
)

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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"
)

View File

@@ -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"
)

View File

@@ -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"

View File

@@ -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"
)

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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{}

View File

@@ -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"

View File

@@ -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
}

View File

@@ -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"

View File

@@ -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"
)

View 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
}

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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
}

View File

@@ -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"

View File

@@ -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"
)

View File

@@ -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"

View File

@@ -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
}

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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
}

View File

@@ -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
//

View File

@@ -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 (

View File

@@ -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
}

View File

@@ -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
//

View File

@@ -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,
}

View File

@@ -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
//

View File

@@ -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,

View File

@@ -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
}

View File

@@ -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):]...)
}
}

View File

@@ -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 {

View File

@@ -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 {

View 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.

View File

@@ -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)
}

View 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)
}

View File

@@ -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",

View 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.

View File

@@ -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.

View File

@@ -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{}
)

View File

@@ -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

View 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
}

View 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>`
)

View 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)
})
}

View 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
}

View File

@@ -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
}

View 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)
}

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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
}

View File

@@ -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
//

View File

@@ -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("生成类型开发中!")

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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

View File

@@ -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
//

View File

@@ -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
//

View File

@@ -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 );")
}

View File

@@ -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))
}

View File

@@ -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)

View File

@@ -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
//

View File

@@ -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
}

View File

@@ -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})
}

View File

@@ -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
//

View File

@@ -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
}

View File

@@ -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

View 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
}

View 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
}
}
}

View 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
}

View 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))
}

View File

@@ -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