模块化上传驱动,使用泛型优化工具库降低冗余

This commit is contained in:
孟帅 2023-06-02 20:29:08 +08:00
parent fdc48b9335
commit 62ecbb7f26
96 changed files with 1276 additions and 1483 deletions

View File

@ -12,27 +12,33 @@ build:
@cd ../web && yarn build && \cp -rf ./dist/* ../server$(ADMIN_RESOURCE_PATH)
@echo "y" | gf build
# 通过热编译启动所有服务
.PHONY: all
all:
gf run main.go --args "all"
.PHONY: http
http:
gf run main.go --args "http"
.PHONY: queue
queue:
gf run main.go --args "queue"
.PHONY: cron
cron:
gf run main.go --args "cron"
.PHONY: auth
auth:
gf run main.go --args "auth"
# 启动web服务
.PHONY: web
web:
@ -44,11 +50,20 @@ web:
refresh:
@go run main.go tools -m=casbin -a1=refresh
# 清理casbin权限
.PHONY: clear
clear:
@go run main.go tools -m=casbin -a1=clear
# 运行代码质量分析工具
# https://github.com/ywanbing/golangci
.PHONY: ci
ci:
golangci-lint run
.PHONY: killmain
killmain:
@kill -9 $(ps -ef|grep main|grep -v grep|awk '{print $2}')
@ -79,11 +94,13 @@ cli.install:
dao: cli.install
@gf gen dao
# Generate Go files for Service.
.PHONY: service
service: cli.install
@gf gen service
# Build image, deploy image and yaml to current kubectl environment and make port forward to local machine.
.PHONY: start
start:
@ -92,6 +109,7 @@ start:
make deploy; \
make port;
# Build docker image.
.PHONY: image
image: cli.install

View File

@ -189,7 +189,7 @@ func (s *sSysTable) Status(ctx context.Context, in sysin.TableStatusInp) (err er
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}
@ -209,7 +209,7 @@ func (s *sSysTable) Switch(ctx context.Context, in sysin.TableSwitchInp) (err er
// ...
}
if !validate.InSliceString(fields, in.Key) {
if !validate.InSlice(fields, in.Key) {
err = gerror.New("开关键名不在白名单")
return
}

View File

@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package sysin
import (
@ -53,7 +52,6 @@ func (in *TableEditInp) Filter(ctx context.Context) (err error) {
if err := g.Validator().Rules("float|between:0,5").Messages("请输入一个浮点数|推荐星只能是0~5星").Data(in.Star).Run(ctx); err != nil {
return err.Current()
}
return
}

View File

@ -15,7 +15,7 @@ import (
)
var (
NoLogin []interface{} // 无需登录
NoLoginRouter []interface{} // 无需登录
LoginRequiredRouter []interface{} // 需要登录
)
@ -23,8 +23,8 @@ var (
func Register(ctx context.Context, group *ghttp.RouterGroup) {
prefix := addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name)
group.Group(prefix, func(group *ghttp.RouterGroup) {
if len(NoLogin) > 0 {
group.Bind(NoLogin...)
if len(NoLoginRouter) > 0 {
group.Bind(NoLoginRouter...)
}
group.Middleware(service.Middleware().AdminAuth)
if len(LoginRequiredRouter) > 0 {

View File

@ -3,17 +3,15 @@
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package attachment
import (
"github.com/gogf/gf/v2/frame/g"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
)
// ListReq 查询列表
// ListReq 查询附件列表
type ListReq struct {
form.PageReq
form.RangeDateReq
@ -28,41 +26,18 @@ type ListRes struct {
form.PageRes
}
// ViewReq 获取信息
// ViewReq 获取附件信息
type ViewReq struct {
Id int64 `json:"id" v:"required#附件ID不能为空" dc:"附件ID"`
g.Meta `path:"/attachment/view" method:"get" tags:"附件" summary:"获取指定信息"`
g.Meta `path:"/attachment/view" method:"get" tags:"附件" summary:"获取指定附件信息"`
}
type ViewRes struct {
*sysin.AttachmentViewModel
}
// EditReq 修改/新增
type EditReq struct {
entity.SysAttachment
g.Meta `path:"/attachment/edit" method:"post" tags:"附件" summary:"修改/新增附件"`
}
type EditRes struct{}
// DeleteReq 删除
// DeleteReq 删除附件
type DeleteReq struct {
Id interface{} `json:"id" v:"required#附件ID不能为空" dc:"附件ID"`
g.Meta `path:"/attachment/delete" method:"post" tags:"附件" summary:"删除附件"`
}
type DeleteRes struct{}
// MaxSortReq 最大排序
type MaxSortReq struct {
Id int64 `json:"id" dc:"附件ID"`
g.Meta `path:"/attachment/maxSort" method:"get" tags:"附件" summary:"附件最大排序"`
}
type MaxSortRes struct {
Sort int `json:"sort" dc:"排序"`
}
// StatusReq 更新状态
type StatusReq struct {
entity.SysAttachment
g.Meta `path:"/attachment/status" method:"post" tags:"附件" summary:"更新附件状态"`
}
type StatusRes struct{}

View File

@ -21,7 +21,7 @@ var (
Http = &gcmd.Command{
Name: "http",
Usage: "http",
Brief: "HTTP服务",
Brief: "HTTP服务也可以称为主服务包含http、websocket、tcpserver多个可对外服务",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
// 加载权限
casbin.InitEnforcer(ctx)
@ -32,6 +32,7 @@ var (
s.BindStatusHandler(404, func(r *ghttp.Request) {
r.Response.Writeln("404 - 你似乎来到了没有知识存在的荒原…")
})
s.BindStatusHandler(403, func(r *ghttp.Request) {
r.Response.Writeln("403 - 网站拒绝显示此网页")
})

View File

@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package consts
// 碎片
@ -12,4 +11,5 @@ const (
DemoTips = "演示系统已隐藏"
NilJsonToString = "{}" // 空json初始化值
RegionSpilt = " / " // 地区分隔符
Unknown = "Unknown"
)

View File

@ -1,7 +1,5 @@
package consts
import "time"
const (
TCPMsgCodeSuccess = 2000 // 成功的状态码
)
@ -21,5 +19,6 @@ const (
)
const (
TCPRpcTimeout = time.Second * 10 // rpc通讯超时时间 默认10s
TCPHeartbeatTimeout = 300 // tcp心跳超时默认300s
TCPRpcTimeout = 10 // rpc通讯超时时间 默认10s
)

View File

@ -5,6 +5,16 @@
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
package consts
// 上传类型
const (
UploadTypeFile = 1 // 文件
UploadTypeImage = 2 // 图片
UploadTypeDoc = 3 // 文档
UploadTypeAudio = 4 // 音频
UploadTypeVideo = 5 // 视频
)
// 上传存储驱动
const (
UploadDriveLocal = "local" // 本地驱动
UploadDriveUCloud = "ucloud" // ucloud对象存储

View File

@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package sys
import (
@ -21,7 +20,7 @@ var (
type cAttachment struct{}
// Delete 删除
// Delete 删除附件
func (c *cAttachment) Delete(ctx context.Context, req *attachment.DeleteReq) (res *attachment.DeleteRes, err error) {
var in sysin.AttachmentDeleteInp
if err = gconv.Scan(req, &in); err != nil {
@ -32,30 +31,7 @@ func (c *cAttachment) Delete(ctx context.Context, req *attachment.DeleteReq) (re
return
}
// Edit 更新
func (c *cAttachment) Edit(ctx context.Context, req *attachment.EditReq) (res *attachment.EditRes, err error) {
var in sysin.AttachmentEditInp
if err = gconv.Scan(req, &in); err != nil {
return
}
err = service.SysAttachment().Edit(ctx, in)
return
}
// MaxSort 最大排序
func (c *cAttachment) MaxSort(ctx context.Context, req *attachment.MaxSortReq) (res *attachment.MaxSortRes, err error) {
data, err := service.SysAttachment().MaxSort(ctx, sysin.AttachmentMaxSortInp{Id: req.Id})
if err != nil {
return
}
res = new(attachment.MaxSortRes)
res.Sort = data.Sort
return
}
// View 获取指定信息
// View 获取指定附件信息
func (c *cAttachment) View(ctx context.Context, req *attachment.ViewReq) (res *attachment.ViewRes, err error) {
data, err := service.SysAttachment().View(ctx, sysin.AttachmentViewInp{Id: req.Id})
if err != nil {
@ -67,7 +43,7 @@ func (c *cAttachment) View(ctx context.Context, req *attachment.ViewReq) (res *a
return
}
// List 查看列表
// List 查看附件列表
func (c *cAttachment) List(ctx context.Context, req *attachment.ListReq) (res *attachment.ListRes, err error) {
var in sysin.AttachmentListInp
if err = gconv.Scan(req, &in); err != nil {
@ -86,14 +62,3 @@ func (c *cAttachment) List(ctx context.Context, req *attachment.ListReq) (res *a
res.PerPage = req.PerPage
return
}
// Status 更新部门状态
func (c *cAttachment) Status(ctx context.Context, req *attachment.StatusReq) (res *attachment.StatusRes, err error) {
var in sysin.AttachmentStatusInp
if err = gconv.Scan(req, &in); err != nil {
return
}
err = service.SysAttachment().Status(ctx, in)
return
}

View File

@ -5,15 +5,7 @@
package dao
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"hotgo/internal/consts"
"hotgo/internal/dao/internal"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/format"
)
// internalSysAttachmentDao is internal type for wrapping internal DAO implements.
@ -31,34 +23,3 @@ var (
internal.NewSysAttachmentDao(),
}
)
func (dao *sysAttachmentDao) GetMd5File(ctx context.Context, md5 string) (data *sysin.AttachmentListModel, err error) {
if err = dao.Ctx(ctx).
Where("md5", md5).
Scan(&data); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
if data == nil {
return nil, nil
}
conf, err := service.SysConfig().GetUpload(ctx)
if err != nil {
return nil, nil
}
data.SizeFormat = format.FileSize(data.Size)
data.FileUrl = service.CommonUpload().LastUrl(ctx, conf, data.FileUrl, data.Drive)
// 只有在上传时才会检查md5值如果文件存在则更新最后上传时间保证上传列表更新显示在最前面
if data.Id > 0 {
_, _ = dao.Ctx(ctx).Where("id", data.Id).Data(g.Map{
"status": consts.StatusEnabled,
"updated_at": gtime.Now(),
}).Update()
}
return data, nil
}

View File

@ -23,10 +23,8 @@ func Tpl(name, tpl string) string {
// 最终效果:/应用名称/插件模块名称/xxx/xxx。如果你不喜欢现在的路由风格可以自行调整
func RouterPrefix(ctx context.Context, app, name string) string {
var prefix = "/"
if app != "" {
prefix = g.Cfg().MustGet(ctx, "router."+app+".prefix", "/"+app+"").String()
}
return prefix + "/" + name
}

View File

@ -91,7 +91,6 @@ func Build(ctx context.Context, sk Skeleton, conf *model.BuildAddonConfig) (err
if err = gfile.PutContents(webViewsPath+"/config/system.vue", gstr.ReplaceByMap(webConfigSystem, replaces)); err != nil {
return
}
return
}

View File

@ -141,6 +141,5 @@ func ModuleSelect() form.Selects {
Name: skeleton.Label,
})
}
return lst
}

View File

@ -104,21 +104,18 @@ func (a *adapter) model() *gdb.Model {
// create a policy table when it's not exists.
func (a *adapter) createPolicyTable() (err error) {
_, err = a.db.Exec(context.TODO(), fmt.Sprintf(createPolicyTableSql, a.table))
return
}
// drop policy table from the storage.
func (a *adapter) dropPolicyTable() (err error) {
_, err = a.db.Exec(context.TODO(), fmt.Sprintf(dropPolicyTableSql, a.table))
return
}
// LoadPolicy loads all policy rules from the storage.
func (a *adapter) LoadPolicy(model model.Model) (err error) {
var rules []policyRule
if err = a.model().Scan(&rules); err != nil {
return
}
@ -126,7 +123,6 @@ func (a *adapter) LoadPolicy(model model.Model) (err error) {
for _, rule := range rules {
a.loadPolicyRule(rule, model)
}
return
}
@ -159,14 +155,12 @@ func (a *adapter) SavePolicy(model model.Model) (err error) {
return
}
}
return
}
// AddPolicy adds a policy rule to the storage.
func (a *adapter) AddPolicy(sec string, ptype string, rule []string) (err error) {
_, err = a.model().Insert(a.buildPolicyRule(ptype, rule))
return
}
@ -183,7 +177,6 @@ func (a *adapter) AddPolicies(sec string, ptype string, rules [][]string) (err e
}
_, err = a.model().Insert(policyRules)
return
}
@ -228,14 +221,12 @@ func (a *adapter) RemovePolicies(sec string, ptype string, rules [][]string) (er
}
_, err = db.Delete()
return
}
// UpdatePolicy updates a policy rule from storage.
func (a *adapter) UpdatePolicy(sec string, ptype string, oldRule, newRule []string) (err error) {
_, err = a.model().Update(a.buildPolicyRule(ptype, newRule), a.buildPolicyRule(ptype, oldRule))
return
}
@ -244,18 +235,14 @@ func (a *adapter) UpdatePolicies(sec string, ptype string, oldRules, newRules []
if len(oldRules) == 0 || len(newRules) == 0 {
return
}
err = a.db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {
return a.db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {
for i := 0; i < int(math.Min(float64(len(oldRules)), float64(len(newRules)))); i++ {
if _, err = tx.Model(a.table).Update(a.buildPolicyRule(ptype, newRules[i]), a.buildPolicyRule(ptype, oldRules[i])); err != nil {
return err
}
}
return nil
})
return
}
// 加载策略规则
@ -285,7 +272,6 @@ func (a *adapter) loadPolicyRule(rule policyRule, model model.Model) {
if rule.V5 != "" {
ruleText += ", " + rule.V5
}
if err := persist.LoadPolicyLine(ruleText, model); err != nil {
panic(err)
}
@ -318,6 +304,5 @@ func (a *adapter) buildPolicyRule(ptype string, data []string) policyRule {
if len(data) > 5 {
rule.V5 = data[5]
}
return rule
}

View File

@ -66,7 +66,6 @@ func GetUser(ctx context.Context) *model.Identity {
if c == nil {
return nil
}
return c.User
}

View File

@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package ems
import (
@ -47,6 +46,5 @@ func sendToMail(config *model.EmailConfig, to, subject, body, mailType string) e
}
msg := []byte("To: " + to + "\r\nFrom: " + config.SendName + "<" + config.User + ">" + "\r\nSubject: " + subject + "\r\n" + contentType + "\r\n\r\n" + body)
return smtp.SendMail(config.Addr, auth, config.User, sendTo, msg)
}

View File

@ -33,7 +33,6 @@ func Dao(ctx context.Context) (err error) {
}
gendao.DoGenDaoForArray(ctx, inp)
}
return
}
@ -126,7 +125,6 @@ func TableSelects(ctx context.Context, in sysin.GenCodesSelectsInp) (res *sysin.
}
res.Addons = addons.ModuleSelect()
return
}
@ -163,7 +161,6 @@ func GenTypeSelect(ctx context.Context) (res sysin.GenTypeSelects, err error) {
res = append(res, row)
}
sort.Sort(res)
return
}

View File

@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package hggen
import (
@ -77,7 +76,6 @@ func GetDaoConfig(group string) gendao.CGenDaoInput {
panic(err)
}
}
return inp
}

View File

@ -81,7 +81,7 @@ func (l *gCurd) generateWebModelDictOptions(ctx context.Context, in *CurdPreview
}
}
dictTypeIds = convert.UniqueSliceInt64(dictTypeIds)
dictTypeIds = convert.UniqueSlice(dictTypeIds)
if len(dictTypeIds) == 0 {
options["has"] = false
return options, nil

View File

@ -108,8 +108,7 @@ func GenJoinSelect(ctx context.Context, entity interface{}, masterDao interface{
continue
}
}
return gstr.Implode(",", convert.UniqueSliceString(tmpFields)), nil
return gstr.Implode(",", convert.UniqueSlice(tmpFields)), nil
}
// GenSelect 生成select
@ -144,8 +143,7 @@ func GenSelect(ctx context.Context, entity interface{}, dao interface{}) (allFie
continue
}
}
return gstr.Implode(",", convert.UniqueSliceString(tmpFields)), nil
return gstr.Implode(",", convert.UniqueSlice(tmpFields)), nil
}
// GetPkField 获取dao实例中的主键名称
@ -163,7 +161,6 @@ func GetPkField(ctx context.Context, dao daoInstance) (string, error) {
return field.Name, nil
}
}
return "", errors.New("no primary key")
}

View File

@ -38,7 +38,6 @@ func FilterAuth(m *gdb.Model) *gdb.Model {
if !needAuth {
return m
}
return m.Handler(FilterAuthWithField(filterField))
}

View File

@ -72,20 +72,19 @@ func WhoisLocation(ctx context.Context, ip string) (*IpLocationData, error) {
return nil, err
}
var whoisData *WhoisRegionData
if err = gconv.Struct([]byte(str), &whoisData); err != nil {
var who *WhoisRegionData
if err = gconv.Struct([]byte(str), &who); err != nil {
return nil, err
}
return &IpLocationData{
Ip: whoisData.Ip,
Region: whoisData.Addr,
Province: whoisData.Pro,
ProvinceCode: gconv.Int64(whoisData.ProCode),
City: whoisData.City,
CityCode: gconv.Int64(whoisData.CityCode),
Area: whoisData.Region,
AreaCode: gconv.Int64(whoisData.RegionCode),
Ip: who.Ip,
Region: who.Addr,
Province: who.Pro,
ProvinceCode: gconv.Int64(who.ProCode),
City: who.City,
CityCode: gconv.Int64(who.CityCode),
Area: who.Region,
AreaCode: gconv.Int64(who.RegionCode),
}, nil
}
@ -159,7 +158,6 @@ func GetLocation(ctx context.Context, ip string) (data *IpLocationData, err erro
}
cacheMap.Set(ip, data)
}
return
}
@ -234,6 +232,5 @@ func GetClientIp(r *ghttp.Request) string {
if gstr.Contains(ip, ", ") {
ip = gstr.StrTillEx(ip, ", ")
}
return ip
}

View File

@ -52,7 +52,6 @@ func ParseSimpleRegion(ctx context.Context, id int64, spilt ...string) (string,
}
return ParseRegion(ctx, ids[0], ids[1], id, spilt...)
}
return "", gerror.New("currently, it is only supported to regional areas")
}
@ -104,6 +103,5 @@ func ParseRegion(ctx context.Context, province int64, city int64, county int64,
if province > 0 && city > 0 {
return provinceName.String() + sp + cityName.String(), nil
}
return provinceName.String(), nil
}

View File

@ -22,41 +22,42 @@ import (
// ClientConfig 客户端配置
type ClientConfig struct {
Addr string
Auth *AuthMeta
Timeout time.Duration
ConnectInterval time.Duration
MaxConnectCount uint
ConnectCount uint
AutoReconnect bool
LoginEvent CallbackEvent
CloseEvent CallbackEvent
Addr string // 连接地址
Auth *AuthMeta // 认证元数据
Timeout time.Duration // 连接超时时间
ConnectInterval time.Duration // 重连时间间隔
MaxConnectCount uint // 最大重连次数0不限次数
ConnectCount uint // 已重连次数
AutoReconnect bool // 是否开启自动重连
LoginEvent CallbackEvent // 登录成功事件
CloseEvent CallbackEvent // 连接关闭事件
}
// Client 客户端
type Client struct {
Ctx context.Context
Logger *glog.Logger
IsLogin bool // 是否已登录
addr string
auth *AuthMeta
rpc *Rpc
timeout time.Duration
connectInterval time.Duration
maxConnectCount uint
connectCount uint
autoReconnect bool
loginEvent CallbackEvent
closeEvent CallbackEvent
sync.Mutex
heartbeat int64
routers map[string]RouterHandler
conn *gtcp.Conn
wg sync.WaitGroup
closeFlag bool // 关闭标签,关闭以后可以重连
stopFlag bool // 停止标签,停止以后不能重连
Ctx context.Context // 上下文
Logger *glog.Logger // 日志处理器
IsLogin bool // 是否已登录
addr string // 连接地址
auth *AuthMeta // 认证元数据
rpc *Rpc // rpc协议支持
timeout time.Duration // 连接超时时间
connectInterval time.Duration // 重连时间间隔
maxConnectCount uint // 最大重连次数0不限次数
connectCount uint // 已重连次数
autoReconnect bool // 是否开启自动重连
loginEvent CallbackEvent // 登录成功事件
closeEvent CallbackEvent // 连接关闭事件
sync.Mutex // 状态锁
heartbeat int64 // 心跳
routers map[string]RouterHandler // 已注册的路由
conn *gtcp.Conn // 连接对象
wg sync.WaitGroup // 状态控制
closeFlag bool // 关闭标签,关闭以后可以重连
stopFlag bool // 停止标签,停止以后不能重连
}
// NewClient 初始化一个tcp客户端
func NewClient(config *ClientConfig) (client *Client, err error) {
client = new(Client)
@ -110,7 +111,7 @@ func NewClient(config *ClientConfig) (client *Client, err error) {
return
}
// Start 启动
// Start 启动tcp连接
func (client *Client) Start() (err error) {
client.Lock()
defer client.Unlock()
@ -133,7 +134,6 @@ func (client *Client) Start() (err error) {
simple.SafeGo(client.Ctx, func(ctx context.Context) {
client.connect()
})
return
}
@ -165,6 +165,7 @@ func (client *Client) RegisterRouter(routers map[string]RouterHandler) (err erro
return
}
// dial
func (client *Client) dial() *gtcp.Conn {
for {
conn, err := gtcp.NewConn(client.addr, client.timeout)
@ -218,6 +219,7 @@ reconnect:
client.startCron()
}
// read
func (client *Client) read() {
simple.SafeGo(client.Ctx, func(ctx context.Context) {
defer func() {
@ -347,7 +349,6 @@ func (client *Client) Write(data interface{}) error {
return gerror.Newf("client json message pointer required: %+v", data)
}
msg := &Message{Router: msgType.Elem().Name(), Data: data}
return SendPkg(client.conn, msg)
}
@ -379,7 +380,6 @@ func (client *Client) RpcRequest(ctx context.Context, data interface{}) (res int
err = gerror.New("traceID is required")
return
}
return client.rpc.Request(key, func() {
_ = client.Write(data)
})

View File

@ -13,21 +13,24 @@ import (
"hotgo/internal/consts"
)
// getCronKey 生成客户端定时任务名称
func (client *Client) getCronKey(s string) string {
return fmt.Sprintf("tcp.client_%s_%s:%s", s, client.auth.Group, client.auth.Name)
}
// stopCron 停止定时任务
func (client *Client) stopCron() {
for _, v := range gcron.Entries() {
gcron.Remove(v.Name)
}
}
// startCron 启动定时任务
func (client *Client) startCron() {
// 心跳超时检查
if gcron.Search(client.getCronKey(consts.TCPCronHeartbeatVerify)) == nil {
_, _ = gcron.AddSingleton(client.Ctx, "@every 600s", func(ctx context.Context) {
if client.heartbeat < gtime.Timestamp()-600 {
if client.heartbeat < gtime.Timestamp()-consts.TCPHeartbeatTimeout {
client.Logger.Debugf(client.Ctx, "client heartbeat timeout, about to reconnect..")
client.Destroy()
}

View File

@ -37,6 +37,7 @@ func (client *Client) serverLogin() {
}
}
// onResponseServerLogin 接收服务登陆响应结果
func (client *Client) onResponseServerLogin(ctx context.Context, args ...interface{}) {
var in *msgin.ResponseServerLogin
if err := gconv.Scan(args[0], &in); err != nil {
@ -58,6 +59,7 @@ func (client *Client) onResponseServerLogin(ctx context.Context, args ...interfa
}
}
// onResponseServerHeartbeat 接收心跳响应结果
func (client *Client) onResponseServerHeartbeat(ctx context.Context, args ...interface{}) {
var in *msgin.ResponseServerHeartbeat
if err := gconv.Scan(args[0], &in); err != nil {

View File

@ -19,6 +19,7 @@ type AuthMeta struct {
EndAt *gtime.Time `json:"-"`
}
// Context tcp上下文
type Context struct {
Conn *gtcp.Conn `json:"conn"`
Auth *AuthMeta `json:"auth"` // 认证元数据

View File

@ -14,8 +14,10 @@ import (
"github.com/gogf/gf/v2/util/gconv"
)
var GoPool = grpool.New(100)
// GoPool 初始化一个协程池,用于处理消息处理
var GoPool = grpool.New(20)
// RouterHandler 路由消息处理器
type RouterHandler func(ctx context.Context, args ...interface{})
// Message 路由消息
@ -24,6 +26,7 @@ type Message struct {
Data interface{} `json:"data"`
}
// SendPkg 打包发送的数据包
func SendPkg(conn *gtcp.Conn, message *Message) error {
b, err := json.Marshal(message)
if err != nil {
@ -32,6 +35,7 @@ func SendPkg(conn *gtcp.Conn, message *Message) error {
return conn.SendPkg(b)
}
// RecvPkg 解包
func RecvPkg(conn *gtcp.Conn) (*Message, error) {
if data, err := conn.RecvPkg(); err != nil {
return nil, err
@ -58,7 +62,6 @@ func MsgPkg(data interface{}, auth *AuthMeta, traceID string) string {
if msg == nil {
return ""
}
return msg.TraceID
}

View File

@ -22,6 +22,7 @@ type Rpc struct {
callbacks map[string]RpcRespFunc
}
// RpcResp 响应结构
type RpcResp struct {
res interface{}
err error
@ -29,6 +30,7 @@ type RpcResp struct {
type RpcRespFunc func(resp interface{}, err error)
// NewRpc 初始化一个rpc协议
func NewRpc(ctx context.Context) *Rpc {
return &Rpc{
ctx: ctx,
@ -57,7 +59,6 @@ func (r *Rpc) HandleMsg(ctx context.Context, cancel context.CancelFunc, data int
})
return true
}
return false
}
@ -99,7 +100,7 @@ func (r *Rpc) Request(callId string, send func()) (res interface{}, err error) {
<-waitCh
select {
case <-time.After(consts.TCPRpcTimeout):
case <-time.After(time.Second * consts.TCPRpcTimeout):
err = gerror.New("rpc response timeout")
return
case got := <-resCh:

View File

@ -19,35 +19,38 @@ import (
"time"
)
// ClientConn 连接到tcp服务器的客户端对象
type ClientConn struct {
Conn *gtcp.Conn
Auth *AuthMeta
heartbeat int64
Conn *gtcp.Conn // 连接对象
Auth *AuthMeta // 认证元数据
heartbeat int64 // 心跳
}
// ServerConfig tcp服务器配置
type ServerConfig struct {
Name string // 服务名称
Addr string // 监听地址
}
// Server tcp服务器对象结构
type Server struct {
Ctx context.Context
Logger *glog.Logger
addr string
name string
rpc *Rpc
ln *gtcp.Server
wgLn sync.WaitGroup
mutex sync.Mutex
closeFlag bool
clients map[string]*ClientConn // 已登录的认证客户端
mutexConns sync.Mutex
wgConns sync.WaitGroup
cronRouters map[string]RouterHandler // 路由
queueRouters map[string]RouterHandler
authRouters map[string]RouterHandler
Ctx context.Context // 上下文
Logger *glog.Logger // 日志处理器
addr string // 连接地址
name string // 服务器名称
rpc *Rpc // rpc协议
ln *gtcp.Server // tcp服务器
wgLn sync.WaitGroup // 状态控制主要用于tcp服务器能够按流程启动退出
mutex sync.Mutex // 服务器状态锁
closeFlag bool // 服务关闭标签
clients map[string]*ClientConn // 已登录的认证客户端
mutexConns sync.Mutex // 连接锁,主要用于客户端上下线
cronRouters map[string]RouterHandler // 定时任务路由
queueRouters map[string]RouterHandler // 队列路由
authRouters map[string]RouterHandler // 任务路由
}
// NewServer 初始一个tcp服务器对象
func NewServer(config *ServerConfig) (server *Server, err error) {
if config == nil {
err = gerror.New("config is nil")
@ -84,6 +87,7 @@ func NewServer(config *ServerConfig) (server *Server, err error) {
return
}
// accept
func (server *Server) accept(conn *gtcp.Conn) {
defer func() {
server.mutexConns.Lock()
@ -262,6 +266,7 @@ func (server *Server) RegisterQueueRouter(routers map[string]RouterHandler) {
}
}
// Listen 监听服务
func (server *Server) Listen() (err error) {
server.wgLn.Add(1)
defer server.wgLn.Done()
@ -283,7 +288,6 @@ func (server *Server) Close() {
}
server.clients = nil
server.mutexConns.Unlock()
server.wgConns.Wait()
if server.ln != nil {
_ = server.ln.Close()

View File

@ -13,16 +13,19 @@ import (
"hotgo/internal/consts"
)
// getCronKey 生成服务端定时任务名称
func (server *Server) getCronKey(s string) string {
return fmt.Sprintf("tcp.server_%s_%s", s, server.name)
}
// stopCron 停止定时任务
func (server *Server) stopCron() {
for _, v := range gcron.Entries() {
gcron.Remove(v.Name)
}
}
// startCron 启动定时任务
func (server *Server) startCron() {
// 心跳超时检查
if gcron.Search(server.getCronKey(consts.TCPCronHeartbeatVerify)) == nil {
@ -31,7 +34,7 @@ func (server *Server) startCron() {
return
}
for _, client := range server.clients {
if client.heartbeat < gtime.Timestamp()-300 {
if client.heartbeat < gtime.Timestamp()-consts.TCPHeartbeatTimeout {
_ = client.Conn.Close()
server.Logger.Debugf(server.Ctx, "client heartbeat timeout, close conn. auth:%+v", client.Auth)
}

View File

@ -17,6 +17,7 @@ import (
"hotgo/utility/convert"
)
// onServerLogin 处理客户端登录
func (server *Server) onServerLogin(ctx context.Context, args ...interface{}) {
var (
in = new(msgin.ServerLogin)
@ -137,6 +138,7 @@ func (server *Server) onServerLogin(ctx context.Context, args ...interface{}) {
_ = server.Write(user.Conn, res)
}
// onServerHeartbeat 处理客户端心跳
func (server *Server) onServerHeartbeat(ctx context.Context, args ...interface{}) {
var (
in *msgin.ServerHeartbeat

View File

@ -93,7 +93,6 @@ func (h *aliPay) Notify(ctx context.Context, in payin.NotifyInp) (res *payin.Not
res.OutTradeNo = notify.OutTradeNo
res.PayAt = notify.GmtPayment
res.ActualAmount = gconv.Float64(notify.ReceiptAmount)
return
}
@ -115,7 +114,6 @@ func (h *aliPay) CreateOrder(ctx context.Context, in payin.CreateOrderInp) (res
default:
err = gerror.Newf("暂未支持的交易方式:%v", in.Pay.TradeType)
}
return
}

View File

@ -44,7 +44,6 @@ func New(name ...string) PayClient {
default:
panic(fmt.Sprintf("暂不支持的支付方式:%v", payType))
}
return client
}

View File

@ -75,7 +75,6 @@ func (h *qqPay) Notify(ctx context.Context, in payin.NotifyInp) (res *payin.Noti
res.OutTradeNo = notify.OutTradeNo
res.PayAt = gtime.New(notify.TimeEnd)
res.ActualAmount = gconv.Float64(notify.CouponFee) / 100 // 用户本次交易中,实际支付的金额 转为元,和系统内保持一至
return
}
@ -119,7 +118,6 @@ func (h *qqPay) CreateOrder(ctx context.Context, in payin.CreateOrderInp) (res *
default:
err = gerror.Newf("暂未支持的交易方式:%v", in.Pay.TradeType)
}
return
}

View File

@ -105,7 +105,6 @@ func (h *wxPay) Notify(ctx context.Context, in payin.NotifyInp) (res *payin.Noti
res.OutTradeNo = notify.OutTradeNo
res.PayAt = gtime.New(notify.SuccessTime)
res.ActualAmount = float64(notify.Amount.PayerTotal / 100) // 转为元,和系统内保持一至
return
}
@ -121,7 +120,6 @@ func (h *wxPay) CreateOrder(ctx context.Context, in payin.CreateOrderInp) (res *
default:
err = gerror.Newf("暂未支持的交易方式:%v", in.Pay.TradeType)
}
return
}

View File

@ -69,5 +69,4 @@ func consumerListen(ctx context.Context, job consumerStrategy) {
}); listenErr != nil {
g.Log().Fatalf(ctx, "消费队列:%s 监听失败, err:%+v", topic, listenErr)
}
}

View File

@ -11,7 +11,8 @@ import (
"github.com/Shopify/sarama"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"hotgo/utility/signal"
"github.com/gogf/gf/v2/os/gproc"
"os"
"time"
)
@ -109,14 +110,13 @@ func (r *KafkaMq) ListenReceiveMsgDo(topic string, receiveDo func(mqMsg MqMsg))
<-consumer.ready
g.Log().Debug(ctx, "kafka consumer up and running!...")
signal.AppDefer(func() {
gproc.AddSigHandlerShutdown(func(sig os.Signal) {
g.Log().Debug(ctx, "kafka consumer close...")
cancel()
if err = r.consumerIns.Close(); err != nil {
g.Log().Fatalf(ctx, "kafka Error closing client, err:%+v", err)
}
})
return
}
@ -203,7 +203,7 @@ func doRegisterKafkaProducer(connOpt KafkaConfig, mqIns *KafkaMq) (err error) {
return
}
signal.AppDefer(func() {
gproc.AddSigHandlerShutdown(func(sig os.Signal) {
g.Log().Debug(ctx, "kafka producer AsyncClose...")
mqIns.producerIns.AsyncClose()
})

View File

@ -0,0 +1,22 @@
package storager
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"hotgo/internal/model"
)
var config *model.UploadConfig
func SetConfig(c *model.UploadConfig) {
config = c
}
func GetConfig() *model.UploadConfig {
return config
}
func GetModel(ctx context.Context) *gdb.Model {
return g.Model("sys_attachment").Ctx(ctx)
}

View File

@ -1,9 +1,9 @@
// Package file
// Package storager
// @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 file
package storager
import (
"github.com/gogf/gf/v2/errors/gerror"
@ -14,7 +14,7 @@ import (
"path"
)
// 文件分类
// 文件归属分类
const (
KindImg = "images" // 图片
KindDoc = "document" // 文档
@ -85,6 +85,24 @@ func IsImgType(ext string) bool {
return ok
}
// IsDocType 判断是否为文档
func IsDocType(ext string) bool {
_, ok := docType[ext]
return ok
}
// IsAudioType 判断是否为音频
func IsAudioType(ext string) bool {
_, ok := audioType[ext]
return ok
}
// IsVideoType 判断是否为视频
func IsVideoType(ext string) bool {
_, ok := videoType[ext]
return ok
}
// GetImgType 获取图片类型
func GetImgType(ext string) (string, error) {
if mime, ok := imgType[ext]; ok {

View File

@ -0,0 +1,12 @@
package storager
// FileMeta 文件元数据
type FileMeta struct {
Filename string // 文件名称
Size int64 // 文件大小
Kind string // 文件所属分类
MetaType string // 文件类型
NaiveType string // NaiveUI类型
Ext string // 文件后缀名
Md5 string // 文件hash
}

View File

@ -0,0 +1,228 @@
package storager
import (
"context"
"fmt"
"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/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/grand"
"hotgo/internal/consts"
"hotgo/internal/library/contexts"
"hotgo/internal/model/entity"
"hotgo/utility/encrypt"
"hotgo/utility/url"
"hotgo/utility/validate"
"strconv"
"strings"
)
// UploadDrive 存储驱动
type UploadDrive interface {
// Upload 上传
Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath string, err error)
}
// New 初始化存储驱动
func New(name ...string) UploadDrive {
var (
driveType = consts.UploadDriveLocal
drive UploadDrive
)
if len(name) > 0 && name[0] != "" {
driveType = name[0]
}
switch driveType {
case consts.UploadDriveLocal:
drive = &LocalDrive{}
case consts.UploadDriveUCloud:
drive = &UCloudDrive{}
case consts.UploadDriveCos:
drive = &CosDrive{}
case consts.UploadDriveOss:
drive = &OssDrive{}
case consts.UploadDriveQiNiu:
drive = &QiNiuDrive{}
default:
panic(fmt.Sprintf("暂不支持的存储驱动:%v", driveType))
}
return drive
}
// DoUpload 上传入口
func DoUpload(ctx context.Context, file *ghttp.UploadFile, typ int) (result *entity.SysAttachment, err error) {
if file == nil {
err = gerror.New("文件必须!")
return
}
meta, err := GetFileMeta(file)
if err != nil {
return
}
if _, err = GetFileType(meta.Ext); err != nil {
return
}
switch typ {
case consts.UploadTypeFile:
if config.FileSize > 0 && meta.Size > config.FileSize*1024*1024 {
err = gerror.Newf("文件大小不能超过%vMB", config.FileSize)
return
}
case consts.UploadTypeImage:
if !IsImgType(meta.Ext) {
err = gerror.New("上传的文件不是图片")
return
}
if config.ImageSize > 0 && meta.Size > config.ImageSize*1024*1024 {
err = gerror.Newf("图片大小不能超过%vMB", config.ImageSize)
return
}
case consts.UploadTypeDoc:
if !IsDocType(meta.Ext) {
err = gerror.New("上传的文件不是文档")
return
}
case consts.UploadTypeAudio:
if !IsAudioType(meta.Ext) {
err = gerror.New("上传的文件不是音频")
return
}
case consts.UploadTypeVideo:
if !IsVideoType(meta.Ext) {
err = gerror.New("上传的文件不是视频")
return
}
default:
err = gerror.Newf("无效的上传类型:%v", typ)
return
}
result, err = hasFile(ctx, meta.Md5)
if err != nil {
return
}
if result != nil {
return
}
// 上传到驱动
fullPath, err := New(config.Drive).Upload(ctx, file)
if err != nil {
return
}
// 写入附件记录
return write(ctx, meta, fullPath)
}
// LastUrl 根据驱动获取最终文件访问地址
func LastUrl(ctx context.Context, fullPath, drive string) string {
if validate.IsURL(fullPath) {
return fullPath
}
switch drive {
case consts.UploadDriveLocal:
return url.GetAddr(ctx) + "/" + fullPath
case consts.UploadDriveUCloud:
return config.UCloudEndpoint + "/" + fullPath
case consts.UploadDriveCos:
return config.CosBucketURL + "/" + fullPath
case consts.UploadDriveOss:
return config.OssBucketURL + "/" + fullPath
case consts.UploadDriveQiNiu:
return config.QiNiuDomain + "/" + fullPath
default:
return fullPath
}
}
// GetFileMeta 获取上传文件元数据
func GetFileMeta(file *ghttp.UploadFile) (meta *FileMeta, err error) {
meta = new(FileMeta)
meta.Filename = file.Filename
meta.Size = file.Size
meta.Ext = Ext(file.Filename)
meta.Kind = GetFileKind(meta.Ext)
meta.MetaType, err = GetFileType(meta.Ext)
if err != nil {
return
}
// 兼容naiveUI
naiveType := "text/plain"
if IsImgType(Ext(file.Filename)) {
naiveType = ""
}
meta.NaiveType = naiveType
// 文件hash
b, err := UploadFileByte(file)
if err != nil {
return
}
meta.Md5 = encrypt.Md5ToString(gconv.String(encrypt.Hash32(b)))
return
}
// GenFullPath 根据目录和文件类型生成一个绝对地址
func GenFullPath(basePath, ext string) string {
fileName := strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6)
fileName = fileName + ext
return basePath + gtime.Date() + "/" + strings.ToLower(fileName)
}
// write 写入附件记录
func write(ctx context.Context, meta *FileMeta, fullPath string) (models *entity.SysAttachment, err error) {
models = &entity.SysAttachment{
Id: 0,
AppId: contexts.GetModule(ctx),
MemberId: contexts.GetUserId(ctx),
Drive: config.Drive,
Size: meta.Size,
Path: fullPath,
FileUrl: fullPath,
Name: meta.Filename,
Kind: meta.Kind,
MetaType: meta.MetaType,
NaiveType: meta.NaiveType,
Ext: meta.Ext,
Md5: meta.Md5,
Status: consts.StatusEnabled,
}
id, err := GetModel(ctx).Data(models).InsertAndGetId()
if err != nil {
return
}
models.Id = id
return
}
// hasFile 检查附件是否存在
func hasFile(ctx context.Context, md5 string) (res *entity.SysAttachment, err error) {
if err = GetModel(ctx).Where("md5", md5).Scan(&res); err != nil {
err = gerror.Wrap(err, "检查文件hash时出现错误")
return
}
if res == nil {
return
}
// 只有在上传时才会检查md5值如果附件存在则更新最后上传时间保证上传列表更新显示在最前面
if res.Id > 0 {
_, _ = GetModel(ctx).WherePri(res.Id).Data(g.Map{
"status": consts.StatusEnabled,
"updated_at": gtime.Now(),
}).Update()
}
return
}

View File

@ -0,0 +1,42 @@
package storager
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gfile"
"github.com/tencentyun/cos-go-sdk-v5"
"net/http"
"net/url"
)
// CosDrive 腾讯云cos驱动
type CosDrive struct {
}
// Upload 上传到腾讯云cos对象存储
func (d *CosDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath string, err error) {
if config.CosPath == "" {
err = gerror.New("COS存储驱动必须配置存储路径!")
return
}
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
URL, _ := url.Parse(config.CosBucketURL)
client := cos.NewClient(&cos.BaseURL{BucketURL: URL}, &http.Client{
Transport: &cos.AuthorizationTransport{
SecretID: config.CosSecretId,
SecretKey: config.CosSecretKey,
},
})
fullPath = GenFullPath(config.UCloudPath, gfile.Ext(file.Filename))
_, err = client.Object.Put(ctx, fullPath, f2, nil)
return
}

View File

@ -0,0 +1,42 @@
package storager
import (
"context"
"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/os/gtime"
"strings"
)
// LocalDrive 本地驱动
type LocalDrive struct {
}
// Upload 上传到本地
func (d *LocalDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath string, err error) {
var (
sp = g.Cfg().MustGet(ctx, "server.serverRoot")
nowDate = gtime.Date()
)
if sp.IsEmpty() {
err = gerror.New("本地上传驱动必须配置静态路径!")
return
}
if config.LocalPath == "" {
err = gerror.New("本地上传驱动必须配置本地存储路径!")
return
}
// 包含静态文件夹的路径
fullDirPath := strings.Trim(sp.String(), "/") + "/" + config.LocalPath + nowDate
fileName, err := file.Save(fullDirPath, true)
if err != nil {
return
}
// 不含静态文件夹的路径
fullPath = config.LocalPath + nowDate + "/" + fileName
return
}

View File

@ -0,0 +1,42 @@
package storager
import (
"context"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gfile"
)
// OssDrive 阿里云oss驱动
type OssDrive struct {
}
// Upload 上传到阿里云oss
func (d *OssDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath string, err error) {
if config.OssPath == "" {
err = gerror.New("OSS存储驱动必须配置存储路径!")
return
}
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
client, err := oss.New(config.OssEndpoint, config.OssSecretId, config.OssSecretKey)
if err != nil {
return
}
bucket, err := client.Bucket(config.OssBucket)
if err != nil {
return
}
fullPath = GenFullPath(config.UCloudPath, gfile.Ext(file.Filename))
err = bucket.PutObject(fullPath, f2)
return
}

View File

@ -0,0 +1,52 @@
package storager
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gfile"
"github.com/qiniu/go-sdk/v7/auth/qbox"
"github.com/qiniu/go-sdk/v7/storage"
)
// QiNiuDrive 七牛云对象存储驱动
type QiNiuDrive struct {
}
// Upload 上传到七牛云对象存储
func (d *QiNiuDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath string, err error) {
if config.QiNiuPath == "" {
err = gerror.New("七牛云存储驱动必须配置存储路径!")
return
}
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
putPolicy := storage.PutPolicy{
Scope: config.QiNiuBucket,
}
token := putPolicy.UploadToken(qbox.NewMac(config.QiNiuAccessKey, config.QiNiuSecretKey))
cfg := storage.Config{}
// 是否使用https域名
cfg.UseHTTPS = true
// 上传是否使用CDN上传加速
cfg.UseCdnDomains = false
// 空间对应的机房
cfg.Region, err = storage.GetRegion(config.QiNiuAccessKey, config.QiNiuBucket)
if err != nil {
return
}
fullPath = GenFullPath(config.UCloudPath, gfile.Ext(file.Filename))
err = storage.NewFormUploader(&cfg).Put(ctx, &storage.PutRet{}, token, fullPath, f2, file.Size, &storage.PutExtra{})
return
}

View File

@ -0,0 +1,45 @@
package storager
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gfile"
upload "github.com/ufilesdk-dev/ufile-gosdk"
)
// UCloudDrive UCloud对象存储驱动
type UCloudDrive struct {
}
// Upload 上传到UCloud对象存储
func (d *UCloudDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath string, err error) {
if config.UCloudPath == "" {
err = gerror.New("UCloud存储驱动必须配置存储路径!")
return
}
client, err := upload.NewFileRequest(&upload.Config{
PublicKey: config.UCloudPublicKey,
PrivateKey: config.UCloudPrivateKey,
BucketHost: config.UCloudBucketHost,
BucketName: config.UCloudBucketName,
FileHost: config.UCloudFileHost,
Endpoint: config.UCloudEndpoint,
VerifyUploadMD5: false,
}, nil)
if err != nil {
return
}
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
fullPath = GenFullPath(config.UCloudPath, gfile.Ext(file.Filename))
err = client.IOPut(f2, fullPath, "")
return
}

View File

@ -223,8 +223,8 @@ func (s *sAdminDept) List(ctx context.Context, in adminin.DeptListInp) (res *adm
}
if len(ids) > 0 {
ids = convert.UniqueSliceInt64(ids)
pids = convert.UniqueSliceInt64(pids)
ids = convert.UniqueSlice(ids)
pids = convert.UniqueSlice(pids)
mod = mod.Wheref(`id in (?) or pid in (?)`, ids, pids)
}

View File

@ -307,6 +307,6 @@ func (s *sAdminMenu) LoginPermissions(ctx context.Context, memberId int64) (list
}
}
lists = convert.UniqueSliceString(lists)
lists = convert.UniqueSlice(lists)
return
}

View File

@ -124,7 +124,7 @@ func (s *sAdminNotice) Status(ctx context.Context, in adminin.NoticeStatusInp) (
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}
@ -322,16 +322,14 @@ func (s *sAdminNotice) UnreadCount(ctx context.Context, in adminin.NoticeUnreadC
// messageIds 获取我的消息所有的消息ID
func (s *sAdminNotice) messageIds(ctx context.Context, memberId int64) (ids []int64, err error) {
mod := s.Model(ctx, &handler.Option{FilterAuth: false}).
array, err := s.Model(ctx, &handler.Option{FilterAuth: false}).
Fields("id").
Where("status", consts.StatusEnabled).
Where("(`type` IN(?) OR (`type` = ? and JSON_CONTAINS(`receiver`,'"+gconv.String(memberId)+"')))",
[]int{consts.NoticeTypeNotify, consts.NoticeTypeNotice}, consts.NoticeTypeLetter,
)
array, err := mod.Array()
).Array()
if err != nil {
return nil, err
return
}
for _, v := range array {
@ -351,14 +349,15 @@ func (s *sAdminNotice) UpRead(ctx context.Context, in adminin.NoticeUpReadInp) (
err = gerror.New("获取用户信息失败!")
return
}
if err = dao.AdminNotice.Ctx(ctx).Where("id", in.Id).Scan(&data); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
return
}
if data == nil {
return gerror.New("公告不存在")
}
return s.updatedReadClicks(ctx, in.Id, memberId)
}
@ -408,13 +407,12 @@ func (s *sAdminNotice) ReadAll(ctx context.Context, in adminin.NoticeReadAllInp)
}
for _, messageId := range messageIds {
if !validate.InSliceInt64(readIds, messageId) {
if !validate.InSlice(readIds, messageId) {
if err = s.updatedReadClicks(ctx, messageId, memberId); err != nil {
return
}
}
}
return
}
@ -435,7 +433,7 @@ func (s *sAdminNotice) updatedReadClicks(ctx context.Context, noticeId, memberId
_, err = dao.AdminNoticeRead.Ctx(ctx).Data(entity.AdminNoticeRead{NoticeId: noticeId, MemberId: memberId}).Insert()
return
}
_, err = dao.AdminNoticeRead.Ctx(ctx).Where(dao.AdminNoticeRead.Columns().Id, models.Id).Increment("clicks", 1)
_, err = dao.AdminNoticeRead.Ctx(ctx).Where(dao.AdminNoticeRead.Columns().Id, models.Id).Increment(dao.AdminNoticeRead.Columns().Clicks, 1)
return
}

View File

@ -382,7 +382,7 @@ func (s *sAdminOrder) Status(ctx context.Context, in adminin.OrderStatusInp) (er
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}

View File

@ -203,7 +203,7 @@ func (s *sAdminPost) Status(ctx context.Context, in adminin.PostStatusInp) (err
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}

View File

@ -57,7 +57,6 @@ func (s *sAdminRole) Verify(ctx context.Context, path, method string) bool {
g.Log().Infof(ctx, "admin Verify Enforce err:%+v", err)
return false
}
return ok
}
@ -102,7 +101,6 @@ func (s *sAdminRole) GetName(ctx context.Context, id int64) (name string, err er
err = gerror.Wrap(err, consts.ErrorORM)
return
}
return r.String(), nil
}
@ -148,7 +146,7 @@ func (s *sAdminRole) UpdatePermissions(ctx context.Context, in adminin.UpdatePer
}
// 去重
in.MenuIds = convert.UniqueSliceInt64(in.MenuIds)
in.MenuIds = convert.UniqueSlice(in.MenuIds)
list := make(g.List, 0, len(in.MenuIds))
for _, v := range in.MenuIds {
@ -169,7 +167,6 @@ func (s *sAdminRole) UpdatePermissions(ctx context.Context, in adminin.UpdatePer
if err != nil {
return
}
return casbin.Refresh(ctx)
}
@ -296,19 +293,18 @@ func (s *sAdminRole) DataScopeEdit(ctx context.Context, in *adminin.DataScopeEdi
return gerror.New("超管角色拥有全部权限,无需修改!")
}
if in.DataScope == consts.RoleDataDeptCustom && len(convert.UniqueSliceInt64(in.CustomDept)) == 0 {
if in.DataScope == consts.RoleDataDeptCustom && len(convert.UniqueSlice(in.CustomDept)) == 0 {
return gerror.New("自定义权限必须配置自定义部门!")
}
models.DataScope = in.DataScope
models.CustomDept = gjson.New(convert.UniqueSliceInt64(in.CustomDept))
models.CustomDept = gjson.New(convert.UniqueSlice(in.CustomDept))
_, err = dao.AdminRole.Ctx(ctx).
Fields(dao.AdminRole.Columns().DataScope, dao.AdminRole.Columns().CustomDept).
Where("id", in.Id).
Data(models).
Update()
return
}

View File

@ -7,33 +7,12 @@ package common
import (
"context"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"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/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/grand"
"github.com/qiniu/go-sdk/v7/auth/qbox"
"github.com/qiniu/go-sdk/v7/storage"
"github.com/tencentyun/cos-go-sdk-v5"
ufile "github.com/ufilesdk-dev/ufile-gosdk"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/model"
"hotgo/internal/library/storager"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/encrypt"
f "hotgo/utility/file"
"hotgo/utility/format"
utilityurl "hotgo/utility/url"
"hotgo/utility/validate"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
type sCommonUpload struct{}
@ -47,391 +26,31 @@ func init() {
}
// UploadFile 上传文件
func (s *sCommonUpload) UploadFile(ctx context.Context, file *ghttp.UploadFile) (result *sysin.AttachmentListModel, err error) {
if file == nil {
err = gerror.New("文件必须!")
return
}
meta, err := s.fileMeta(file)
func (s *sCommonUpload) UploadFile(ctx context.Context, file *ghttp.UploadFile) (res *sysin.AttachmentListModel, err error) {
attachment, err := storager.DoUpload(ctx, file, consts.UploadTypeFile)
if err != nil {
return
}
if _, err = f.GetFileType(meta.Ext); err != nil {
return
}
result, err = s.HasFile(ctx, meta.Md5)
if err != nil {
return
}
if result != nil {
return
}
conf, err := service.SysConfig().GetUpload(ctx)
if err != nil {
return
}
switch conf.Drive {
case consts.UploadDriveLocal:
return s.UploadLocal(ctx, conf, file, meta)
case consts.UploadDriveUCloud:
return s.UploadUCloud(ctx, conf, file, meta)
case consts.UploadDriveCos:
return s.UploadCOS(ctx, conf, file, meta)
case consts.UploadDriveOss:
return s.UploadOSS(ctx, conf, file, meta)
case consts.UploadDriveQiNiu:
return s.UploadQiNiu(ctx, conf, file, meta)
default:
return nil, gerror.Newf("暂不支持上传驱动:%v", conf.Drive)
attachment.FileUrl = storager.LastUrl(ctx, attachment.FileUrl, attachment.Drive)
res = &sysin.AttachmentListModel{
SysAttachment: *attachment,
SizeFormat: format.FileSize(attachment.Size),
}
return
}
// UploadImage 上传图片
func (s *sCommonUpload) UploadImage(ctx context.Context, file *ghttp.UploadFile) (result *sysin.AttachmentListModel, err error) {
if file == nil {
err = gerror.New("文件必须!")
return
}
meta, err := s.fileMeta(file)
func (s *sCommonUpload) UploadImage(ctx context.Context, file *ghttp.UploadFile) (res *sysin.AttachmentListModel, err error) {
attachment, err := storager.DoUpload(ctx, file, consts.UploadTypeImage)
if err != nil {
return
}
if !f.IsImgType(meta.Ext) {
err = gerror.New("上传的文件不是图片")
return
}
if meta.Size > 2*1024*1024 {
err = gerror.New("图片大小不能超过2MB")
return
}
result, err = s.HasFile(ctx, meta.Md5)
if err != nil {
return
}
if result != nil {
return
}
conf, err := service.SysConfig().GetUpload(ctx)
if err != nil {
return
}
switch conf.Drive {
case consts.UploadDriveLocal:
return s.UploadLocal(ctx, conf, file, meta)
case consts.UploadDriveUCloud:
return s.UploadUCloud(ctx, conf, file, meta)
case consts.UploadDriveCos:
return s.UploadCOS(ctx, conf, file, meta)
case consts.UploadDriveOss:
return s.UploadOSS(ctx, conf, file, meta)
case consts.UploadDriveQiNiu:
return s.UploadQiNiu(ctx, conf, file, meta)
default:
err = gerror.Newf("暂不支持上传驱动:%v", conf.Drive)
return
}
}
// UploadLocal 上传本地
func (s *sCommonUpload) UploadLocal(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error) {
var (
value = g.Cfg().MustGet(ctx, "server.serverRoot")
nowDate = time.Now().Format("2006-01-02")
)
if value.IsEmpty() {
err = gerror.New("本地上传驱动必须配置静态路径!")
return
}
if conf.LocalPath == "" {
err = gerror.New("本地上传驱动必须配置本地存储路径!")
return
}
// 包含静态文件夹的路径
fullDirPath := strings.Trim(value.String(), "/") + "/" + conf.LocalPath + nowDate
fileName, err := file.Save(fullDirPath, true)
if err != nil {
return
}
// 不含静态文件夹的路径
fullPath := conf.LocalPath + nowDate + "/" + fileName
attachment, err := service.SysAttachment().Add(ctx, meta, fullPath, consts.UploadDriveLocal)
if err != nil {
return
}
attachment.FileUrl = s.LastUrl(ctx, conf, attachment.FileUrl, attachment.Drive)
result = &sysin.AttachmentListModel{
attachment.FileUrl = storager.LastUrl(ctx, attachment.FileUrl, attachment.Drive)
res = &sysin.AttachmentListModel{
SysAttachment: *attachment,
SizeFormat: format.FileSize(attachment.Size),
}
return
}
// UploadUCloud 上传UCloud对象存储
func (s *sCommonUpload) UploadUCloud(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error) {
if conf.UCloudPath == "" {
err = gerror.New("UCloud存储驱动必须配置存储路径!")
return
}
nowDate := time.Now().Format("2006-01-02")
fileName := strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))
fileName = fileName + gfile.Ext(file.Filename)
fullPath := conf.UCloudPath + nowDate + "/" + fileName
config := &ufile.Config{
PublicKey: conf.UCloudPublicKey,
PrivateKey: conf.UCloudPrivateKey,
BucketHost: conf.UCloudBucketHost,
BucketName: conf.UCloudBucketName,
FileHost: conf.UCloudFileHost,
Endpoint: conf.UCloudEndpoint,
VerifyUploadMD5: false,
}
req, err := ufile.NewFileRequest(config, nil)
if err != nil {
return
}
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
if err = req.IOPut(f2, fullPath, ""); err != nil {
return
}
attachment, err := service.SysAttachment().Add(ctx, meta, fullPath, consts.UploadDriveUCloud)
if err != nil {
return
}
attachment.FileUrl = s.LastUrl(ctx, conf, attachment.FileUrl, attachment.Drive)
result = &sysin.AttachmentListModel{
SysAttachment: *attachment,
SizeFormat: format.FileSize(attachment.Size),
}
return
}
// UploadCOS 上传腾讯云对象存储
func (s *sCommonUpload) UploadCOS(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error) {
if conf.CosPath == "" {
err = gerror.New("COS存储驱动必须配置存储路径!")
return
}
nowDate := time.Now().Format("2006-01-02")
fileName := strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))
fileName = fileName + gfile.Ext(file.Filename)
fullPath := conf.CosPath + nowDate + "/" + fileName
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
u, _ := url.Parse(conf.CosBucketURL)
b := &cos.BaseURL{BucketURL: u}
c := cos.NewClient(b, &http.Client{
Transport: &cos.AuthorizationTransport{
SecretID: conf.CosSecretId,
SecretKey: conf.CosSecretKey,
},
})
if _, err = c.Object.Put(ctx, fullPath, f2, nil); err != nil {
return
}
attachment, err := service.SysAttachment().Add(ctx, meta, fullPath, consts.UploadDriveCos)
if err != nil {
return
}
attachment.FileUrl = s.LastUrl(ctx, conf, attachment.FileUrl, attachment.Drive)
result = &sysin.AttachmentListModel{
SysAttachment: *attachment,
SizeFormat: format.FileSize(attachment.Size),
}
return
}
// UploadOSS 上传阿里云云对象存储
func (s *sCommonUpload) UploadOSS(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error) {
if conf.OssPath == "" {
err = gerror.New("OSS存储驱动必须配置存储路径!")
return
}
nowDate := time.Now().Format("2006-01-02")
fileName := strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))
fileName = fileName + gfile.Ext(file.Filename)
fullPath := conf.OssPath + nowDate + "/" + fileName
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
client, err := oss.New(conf.OssEndpoint, conf.OssSecretId, conf.OssSecretKey)
if err != nil {
return
}
bucket, err := client.Bucket(conf.OssBucket)
if err != nil {
return
}
if err = bucket.PutObject(fullPath, f2); err != nil {
return
}
attachment, err := service.SysAttachment().Add(ctx, meta, fullPath, consts.UploadDriveOss)
if err != nil {
return
}
attachment.FileUrl = s.LastUrl(ctx, conf, attachment.FileUrl, attachment.Drive)
result = &sysin.AttachmentListModel{
SysAttachment: *attachment,
SizeFormat: format.FileSize(attachment.Size),
}
return
}
// UploadQiNiu 上传七牛云对象存储
func (s *sCommonUpload) UploadQiNiu(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error) {
if conf.QiNiuPath == "" {
err = gerror.New("七牛云存储驱动必须配置存储路径!")
return
}
nowDate := time.Now().Format("2006-01-02")
fileName := strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))
fileName = fileName + gfile.Ext(file.Filename)
fullPath := conf.QiNiuPath + nowDate + "/" + fileName
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
putPolicy := storage.PutPolicy{
Scope: conf.QiNiuBucket,
}
token := putPolicy.UploadToken(qbox.NewMac(conf.QiNiuAccessKey, conf.QiNiuSecretKey))
cfg := storage.Config{}
// 是否使用https域名
cfg.UseHTTPS = true
// 上传是否使用CDN上传加速
cfg.UseCdnDomains = false
// 空间对应的机房
cfg.Region, err = storage.GetRegion(conf.QiNiuAccessKey, conf.QiNiuBucket)
if err != nil {
return
}
if err = storage.NewFormUploader(&cfg).Put(ctx, &storage.PutRet{}, token, fullPath, f2, file.Size, &storage.PutExtra{}); err != nil {
return
}
attachment, err := service.SysAttachment().Add(ctx, meta, fullPath, consts.UploadDriveQiNiu)
if err != nil {
return
}
attachment.FileUrl = s.LastUrl(ctx, conf, attachment.FileUrl, attachment.Drive)
result = &sysin.AttachmentListModel{
SysAttachment: *attachment,
SizeFormat: format.FileSize(attachment.Size),
}
return
}
// LastUrl 根据驱动获取最终文件访问地址
func (s *sCommonUpload) LastUrl(ctx context.Context, conf *model.UploadConfig, fullPath, drive string) string {
if validate.IsURL(fullPath) {
return fullPath
}
switch drive {
case consts.UploadDriveLocal:
return utilityurl.GetAddr(ctx) + "/" + fullPath
case consts.UploadDriveUCloud:
return conf.UCloudEndpoint + "/" + fullPath
case consts.UploadDriveCos:
return conf.CosBucketURL + "/" + fullPath
case consts.UploadDriveOss:
return conf.OssBucketURL + "/" + fullPath
case consts.UploadDriveQiNiu:
return conf.QiNiuDomain + "/" + fullPath
default:
return fullPath
}
}
// HasFile 文件是否存在
func (s *sCommonUpload) HasFile(ctx context.Context, md5 string) (res *sysin.AttachmentListModel, err error) {
res, err = dao.SysAttachment.GetMd5File(ctx, md5)
return
}
// fileMeta 上传文件元数据
func (s *sCommonUpload) fileMeta(file *ghttp.UploadFile) (meta *sysin.UploadFileMeta, err error) {
meta = new(sysin.UploadFileMeta)
meta.Filename = file.Filename
meta.Size = file.Size
meta.Ext = f.Ext(file.Filename)
meta.Kind = f.GetFileKind(meta.Ext)
meta.MetaType, err = f.GetFileType(meta.Ext)
if err != nil {
return
}
// 兼容naiveUI
naiveType := "text/plain"
if f.IsImgType(f.Ext(file.Filename)) {
naiveType = ""
}
meta.NaiveType = naiveType
// 文件hash
b, err := f.UploadFileByte(file)
if err != nil {
return
}
meta.Md5 = encrypt.Md5ToString(gconv.String(encrypt.Hash32(b)))
return
}

View File

@ -32,7 +32,6 @@ func (s *sMiddleware) AdminAuth(r *ghttp.Request) {
// 将用户信息传递到上下文中
if err := deliverUserContext(r); err != nil {
g.Log().Warningf(ctx, "deliverUserContext err:%+v", err)
response.JsonExit(r, gcode.CodeNotAuthorized.Code(), err.Error())
return
}

View File

@ -138,7 +138,7 @@ func (s *sPay) Status(ctx context.Context, in payin.PayStatusInp) (err error) {
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}

View File

@ -90,7 +90,6 @@ func (s *sSysAddons) List(ctx context.Context, in sysin.AddonsListInp) (list []*
}
totalCount = len(sks)
return
}
@ -129,7 +128,6 @@ func (s *sSysAddons) Build(ctx context.Context, in sysin.AddonsBuildInp) (err er
err = gerror.New("没有找到有效的生成或插件配置,请检查配置文件是否正常")
return
}
return addons.Build(ctx, in.Skeleton, genConfig.Addon)
}

View File

@ -54,8 +54,8 @@ func (s *sSysAddonsConfig) GetConfigByGroup(ctx context.Context, in sysin.GetAdd
Scan(&models); err != nil {
return nil, err
}
isDemo := g.Cfg().MustGet(ctx, "hotgo.isDemo", false)
isDemo := g.Cfg().MustGet(ctx, "hotgo.isDemo", false)
if len(models) > 0 {
res = new(sysin.GetAddonsConfigModel)
res.List = make(g.Map, len(models))
@ -71,7 +71,6 @@ func (s *sSysAddonsConfig) GetConfigByGroup(ctx context.Context, in sysin.GetAdd
}
}
}
return
}
@ -105,10 +104,10 @@ func (s *sSysAddonsConfig) UpdateConfigByGroup(ctx context.Context, in sysin.Upd
Where("addon_name", in.AddonName).
Where("group", in.Group).
Scan(&models); err != nil {
return err
return
}
err = dao.SysAddonsConfig.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = dao.SysAddonsConfig.Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
for k, v := range in.List {
row := s.getConfigByKey(k, models)
// 新增
@ -130,20 +129,15 @@ func (s *sSysAddonsConfig) UpdateConfigByGroup(ctx context.Context, in sysin.Upd
}
// 更新
_, err = dao.SysAddonsConfig.Ctx(ctx).Where("id", row.Id).Data(g.Map{"value": v, "updated_at": gtime.Now()}).Update()
if err != nil {
if _, err = dao.SysAddonsConfig.Ctx(ctx).Where("id", row.Id).Data(g.Map{"value": v, "updated_at": gtime.Now()}).Update(); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
return
}
}
return nil
return
})
if err != nil {
return err
}
return nil
return
}
func (s *sSysAddonsConfig) getConfigByKey(key string, models []*entity.SysAddonsConfig) *entity.SysAddonsConfig {
@ -156,6 +150,5 @@ func (s *sSysAddonsConfig) getConfigByKey(key string, models []*entity.SysAddons
return v
}
}
return nil
}

View File

@ -9,17 +9,12 @@ import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gtime"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/contexts"
"hotgo/internal/library/hgorm/handler"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/form"
"hotgo/internal/library/storager"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/format"
"hotgo/utility/validate"
)
type sSysAttachment struct{}
@ -37,92 +32,41 @@ func (s *sSysAttachment) Model(ctx context.Context, option ...*handler.Option) *
return handler.Model(dao.SysAttachment.Ctx(ctx), option...)
}
// Delete 删除
// Delete 删除附件
func (s *sSysAttachment) Delete(ctx context.Context, in sysin.AttachmentDeleteInp) (err error) {
_, err = s.Model(ctx).Where("id", in.Id).Delete()
if _, err = s.Model(ctx).WherePri(in.Id).Delete(); err != nil {
err = gerror.Wrap(err, "删除附件失败,请稍后重试!")
}
return
}
// Edit 修改/新增
func (s *sSysAttachment) Edit(ctx context.Context, in sysin.AttachmentEditInp) (err error) {
if in.Name == "" {
err = gerror.New("标题不能为空")
return
}
// 修改
if in.Id > 0 {
_, err = s.Model(ctx).Where("id", in.Id).Data(in).Update()
return
}
// 新增
_, err = dao.SysAttachment.Ctx(ctx).Data(in).Insert()
return
}
// Status 更新部门状态
func (s *sSysAttachment) Status(ctx context.Context, in sysin.AttachmentStatusInp) (err error) {
if in.Id <= 0 {
err = gerror.New("ID不能为空")
return
}
if in.Status <= 0 {
err = gerror.New("状态不能为空")
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}
// 修改
_, err = s.Model(ctx).Where("id", in.Id).Data("status", in.Status).Update()
return
}
// MaxSort 最大排序
func (s *sSysAttachment) MaxSort(ctx context.Context, in sysin.AttachmentMaxSortInp) (res *sysin.AttachmentMaxSortModel, err error) {
if in.Id > 0 {
if err = s.Model(ctx).Where("id", in.Id).Order("sort desc").Scan(&res); err != nil {
return
}
}
if res == nil {
res = new(sysin.AttachmentMaxSortModel)
}
res.Sort = form.DefaultMaxSort(ctx, res.Sort)
return
}
// View 获取指定字典类型信息
// View 获取附件信息
func (s *sSysAttachment) View(ctx context.Context, in sysin.AttachmentViewInp) (res *sysin.AttachmentViewModel, err error) {
err = s.Model(ctx).Where("id", in.Id).Scan(&res)
if err = s.Model(ctx).WherePri(in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, "获取附件信息失败,请稍后重试!")
}
return
}
// List 获取列表
// List 获取附件列表
func (s *sSysAttachment) List(ctx context.Context, in sysin.AttachmentListInp) (list []*sysin.AttachmentListModel, totalCount int, err error) {
mod := s.Model(ctx)
if in.MemberId > 0 {
mod = mod.Where("member_id", in.MemberId)
mod = mod.Where(dao.SysAttachment.Columns().MemberId, in.MemberId)
}
if in.Drive != "" {
mod = mod.Where("drive", in.Drive)
mod = mod.Where(dao.SysAttachment.Columns().Drive, in.Drive)
}
if in.Status > 0 {
mod = mod.Where("status", in.Status)
mod = mod.Where(dao.SysAttachment.Columns().Status, in.Status)
}
totalCount, err = mod.Count()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
err = gerror.Wrap(err, "获取附件数据行失败!")
return
}
@ -130,58 +74,14 @@ func (s *sSysAttachment) List(ctx context.Context, in sysin.AttachmentListInp) (
return
}
if err = mod.Page(in.Page, in.PerPage).Order("updated_at desc").Scan(&list); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return
}
conf, err := service.SysConfig().GetUpload(ctx)
if err != nil {
if err = mod.Page(in.Page, in.PerPage).OrderDesc(dao.SysAttachment.Columns().UpdatedAt).Scan(&list); err != nil {
err = gerror.Wrap(err, "获取附件列表失败!")
return
}
for _, v := range list {
v.SizeFormat = format.FileSize(v.Size)
v.FileUrl = service.CommonUpload().LastUrl(ctx, conf, v.FileUrl, v.Drive)
v.FileUrl = storager.LastUrl(ctx, v.FileUrl, v.Drive)
}
return
}
// Add 新增附件
func (s *sSysAttachment) Add(ctx context.Context, meta *sysin.UploadFileMeta, fullPath, drive string) (models *entity.SysAttachment, err error) {
var (
c = contexts.Get(ctx)
user = c.User
memberId int64 = 0
)
if user != nil {
memberId = user.Id
}
models = &entity.SysAttachment{
Id: 0,
AppId: c.Module,
MemberId: memberId,
Drive: drive,
Size: meta.Size,
Path: fullPath,
FileUrl: fullPath,
Name: meta.Filename,
Kind: meta.Kind,
MetaType: meta.MetaType,
NaiveType: meta.NaiveType,
Ext: meta.Ext,
Md5: meta.Md5,
Status: consts.StatusEnabled,
CreatedAt: gtime.Now(),
UpdatedAt: gtime.Now(),
}
id, err := dao.SysAttachment.Ctx(ctx).Data(models).InsertAndGetId()
if err != nil {
return
}
models.Id = id
return
}

View File

@ -71,7 +71,7 @@ func (s *sSysBlacklist) Status(ctx context.Context, in sysin.BlacklistStatusInp)
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}

View File

@ -16,6 +16,7 @@ import (
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/payment"
"hotgo/internal/library/storager"
"hotgo/internal/library/token"
"hotgo/internal/library/wechat"
"hotgo/internal/model"
@ -35,6 +36,7 @@ func init() {
service.RegisterSysConfig(NewSysConfig())
}
// InitConfig 初始化一些系统启动就需要用到的配置
func (s *sSysConfig) InitConfig(ctx context.Context) {
wx, err := s.GetWechat(ctx)
if err != nil {
@ -48,12 +50,17 @@ func (s *sSysConfig) InitConfig(ctx context.Context) {
}
payment.SetConfig(pay)
upload, err := s.GetUpload(ctx)
if err != nil {
g.Log().Fatalf(ctx, "init upload conifg fail%+v", err)
}
storager.SetConfig(upload)
tk, err := s.GetLoadToken(ctx)
if err != nil {
g.Log().Fatalf(ctx, "init token conifg fail%+v", err)
}
token.SetConfig(tk)
}
// GetLogin 获取登录配置
@ -267,7 +274,6 @@ func (s *sSysConfig) UpdateConfigByGroup(ctx context.Context, in sysin.UpdateCon
return s.syncUpdate(ctx, in)
})
return
}
@ -281,7 +287,6 @@ func (s *sSysConfig) getConfigByKey(key string, models []*entity.SysConfig) *ent
return v
}
}
return nil
}
@ -298,6 +303,11 @@ func (s *sSysConfig) syncUpdate(ctx context.Context, in sysin.UpdateConfigInp) (
if err == nil {
payment.SetConfig(pay)
}
case "upload":
upload, err := s.GetUpload(ctx)
if err == nil {
storager.SetConfig(upload)
}
}
if err != nil {

View File

@ -106,7 +106,7 @@ func (s *sSysCron) Status(ctx context.Context, in sysin.CronStatusInp) (err erro
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}

View File

@ -46,7 +46,6 @@ func (s *sSysCronGroup) Edit(ctx context.Context, in sysin.CronGroupEditInp) (er
if _, err = dao.SysCronGroup.Ctx(ctx).Fields(sysin.CronGroupInsertFields{}).Data(in).Insert(); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
}
return
}

View File

@ -198,7 +198,7 @@ func (s *sSysCurdDemo) Switch(ctx context.Context, in sysin.CurdDemoSwitchInp) (
// ...
}
if !validate.InSliceString(fields, in.Key) {
if !validate.InSlice(fields, in.Key) {
err = gerror.New("开关键名不在白名单")
return
}

View File

@ -44,7 +44,6 @@ func (s *sSysDictData) Edit(ctx context.Context, in sysin.DictDataEditInp) (err
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}

View File

@ -76,7 +76,7 @@ func (s *sSysEmsLog) Status(ctx context.Context, in sysin.EmsLogStatusInp) (err
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}

View File

@ -110,7 +110,7 @@ func (s *sSysGenCodes) Status(ctx context.Context, in sysin.GenCodesStatusInp) (
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}
@ -274,7 +274,6 @@ func (s *sSysGenCodes) ColumnSelect(ctx context.Context, in sysin.GenCodesColumn
res[k].Name = fmt.Sprintf("%s (%s)", v.Value, v.Label)
res[k].Label = res[k].Name
}
return
}
@ -306,6 +305,5 @@ func (s *sSysGenCodes) Build(ctx context.Context, in sysin.GenCodesBuildInp) (er
_ = s.Status(ctx, sysin.GenCodesStatusInp{Id: in.Id, Status: consts.GenCodesStatusFail})
return err
}
return
}

View File

@ -230,7 +230,6 @@ func (s *sSysLog) AnalysisLog(ctx context.Context) entity.SysLog {
Status: consts.StatusEnabled,
TakeUpTime: takeUpTime,
}
return data
}
@ -241,8 +240,7 @@ func (s *sSysLog) View(ctx context.Context, in sysin.LogViewInp) (res *sysin.Log
return
}
isDemo := g.Cfg().MustGet(ctx, "hotgo.isDemo", false)
if isDemo.Bool() {
if g.Cfg().MustGet(ctx, "hotgo.isDemo", false).Bool() {
res.HeaderData = gjson.New(`{
"none": [
"` + consts.DemoTips + `"
@ -364,6 +362,5 @@ func (s *sSysLog) List(ctx context.Context, in sysin.LogListInp) (list []*sysin.
}
}
return
}

View File

@ -107,7 +107,6 @@ func (s *sSysLoginLog) List(ctx context.Context, in sysin.LoginLogListInp) (list
v.Os = useragent.GetOs(v.SysLogUserAgent)
v.Browser = useragent.GetBrowser(v.SysLogUserAgent)
}
return
}

View File

@ -71,7 +71,7 @@ func (s *sSysSmsLog) Status(ctx context.Context, in sysin.SmsLogStatusInp) (err
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}

View File

@ -3,11 +3,9 @@
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package view
import (
"fmt"
"hotgo/internal/consts"
"github.com/gogf/gf/v2/net/ghttp"
@ -44,41 +42,6 @@ func (s *viewBuildIn) UrlPath() string {
return s.httpRequest.URL.Path
}
// FormatTime 格式化时间
func (s *viewBuildIn) FormatTime(gt *gtime.Time) string {
if gt == nil {
return ""
}
n := gtime.Now().Timestamp()
t := gt.Timestamp()
var ys int64 = 31536000
var ds int64 = 86400
var hs int64 = 3600
var ms int64 = 60
var ss int64 = 1
var rs string
d := n - t
switch {
case d > ys:
rs = fmt.Sprintf("%d年前", int(d/ys))
case d > ds:
rs = fmt.Sprintf("%d天前", int(d/ds))
case d > hs:
rs = fmt.Sprintf("%d小时前", int(d/hs))
case d > ms:
rs = fmt.Sprintf("%d分钟前", int(d/ms))
case d > ss:
rs = fmt.Sprintf("%d秒前", int(d/ss))
default:
rs = "刚刚"
}
return rs
}
// Version 随机数 开发环境时间戳,线上为前端版本号
func (s *viewBuildIn) Version() string {
var rand string

View File

@ -124,7 +124,7 @@ func (in *DeptStatusInp) Filter(ctx context.Context) (err error) {
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}

View File

@ -225,7 +225,7 @@ func (in *MemberStatusInp) Filter(ctx context.Context) (err error) {
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}

View File

@ -25,7 +25,7 @@ type OrderAcceptRefundInp struct {
}
func (in *OrderAcceptRefundInp) Filter(ctx context.Context) (err error) {
if !validate.InSliceInt64(consts.OrderStatusSlice, in.Status) {
if !validate.InSlice(consts.OrderStatusSlice, in.Status) {
err = gerror.Newf("订单状态不正确")
return
}

View File

@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package sysin
import (
@ -11,28 +10,13 @@ import (
"hotgo/internal/model/input/form"
)
// AttachmentMaxSortInp 最大排序
type AttachmentMaxSortInp struct {
Id int64
}
type AttachmentMaxSortModel struct {
Sort int
}
// AttachmentEditInp 修改/新增字典数据
type AttachmentEditInp struct {
entity.SysAttachment
}
type AttachmentEditModel struct{}
// AttachmentDeleteInp 删除字典类型
// AttachmentDeleteInp 删除附件
type AttachmentDeleteInp struct {
Id interface{}
}
type AttachmentDeleteModel struct{}
// AttachmentViewInp 获取信息
// AttachmentViewInp 获取附件信息
type AttachmentViewInp struct {
Id int64
}
@ -41,7 +25,7 @@ type AttachmentViewModel struct {
entity.SysAttachment
}
// AttachmentListInp 获取列表
// AttachmentListInp 获取附件列表
type AttachmentListInp struct {
form.PageReq
form.RangeDateReq
@ -54,19 +38,3 @@ type AttachmentListModel struct {
entity.SysAttachment
SizeFormat string `json:"sizeFormat" description:"长度"`
}
// AttachmentStatusInp 更新状态
type AttachmentStatusInp struct {
entity.SysAttachment
}
type AttachmentStatusModel struct{}
type UploadFileMeta struct {
Filename string
Size int64
Kind string
MetaType string
NaiveType string
Ext string
Md5 string
}

View File

@ -108,7 +108,7 @@ func (in *CronGroupStatusInp) Filter(ctx context.Context) (err error) {
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}

View File

@ -186,7 +186,7 @@ func (in *CurdDemoStatusInp) Filter(ctx context.Context) (err error) {
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}

View File

@ -114,7 +114,7 @@ func (in *ProvincesStatusInp) Filter(ctx context.Context) (err error) {
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}

View File

@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package genrouter
import (
@ -14,7 +13,7 @@ import (
)
var (
NoLogin []interface{} // 无需登录
NoLoginRouter []interface{} // 无需登录
LoginRequiredRouter []interface{} // 需要登录
)
@ -22,8 +21,8 @@ var (
func Register(ctx context.Context, group *ghttp.RouterGroup) {
prefix := g.Cfg().MustGet(ctx, "router.admin.prefix", "/admin")
group.Group(prefix.String(), func(group *ghttp.RouterGroup) {
if len(NoLogin) > 0 {
group.Bind(NoLogin...)
if len(NoLoginRouter) > 0 {
group.Bind(NoLoginRouter...)
}
group.Middleware(service.Middleware().AdminAuth)
if len(LoginRequiredRouter) > 0 {

View File

@ -19,6 +19,68 @@ import (
)
type (
IAdminMember interface {
AddBalance(ctx context.Context, in adminin.MemberAddBalanceInp) (err error)
AddIntegral(ctx context.Context, in adminin.MemberAddIntegralInp) (err error)
UpdateCash(ctx context.Context, in adminin.MemberUpdateCashInp) (err error)
UpdateEmail(ctx context.Context, in adminin.MemberUpdateEmailInp) (err error)
UpdateMobile(ctx context.Context, in adminin.MemberUpdateMobileInp) (err error)
UpdateProfile(ctx context.Context, in adminin.MemberUpdateProfileInp) (err error)
UpdatePwd(ctx context.Context, in adminin.MemberUpdatePwdInp) (err error)
ResetPwd(ctx context.Context, in adminin.MemberResetPwdInp) (err error)
VerifyUnique(ctx context.Context, in adminin.VerifyUniqueInp) (err error)
Delete(ctx context.Context, in adminin.MemberDeleteInp) (err error)
Edit(ctx context.Context, in adminin.MemberEditInp) (err error)
View(ctx context.Context, in adminin.MemberViewInp) (res *adminin.MemberViewModel, err error)
List(ctx context.Context, in adminin.MemberListInp) (list []*adminin.MemberListModel, totalCount int, err error)
Status(ctx context.Context, in adminin.MemberStatusInp) (err error)
GenTree(ctx context.Context, pid int64) (level int, newTree string, err error)
LoginMemberInfo(ctx context.Context) (res *adminin.LoginMemberInfoModel, err error)
MemberLoginStat(ctx context.Context, in adminin.MemberLoginStatInp) (res *adminin.MemberLoginStatModel, err error)
GetIdByCode(ctx context.Context, in adminin.GetIdByCodeInp) (res *adminin.GetIdByCodeModel, err error)
Select(ctx context.Context, in adminin.MemberSelectInp) (res []*adminin.MemberSelectModel, err error)
VerifySuperId(ctx context.Context, verifyId int64) bool
FilterAuthModel(ctx context.Context, memberId int64) *gdb.Model
}
IAdminMemberPost interface {
UpdatePostIds(ctx context.Context, memberId int64, postIds []int64) (err error)
}
IAdminMenu interface {
MaxSort(ctx context.Context, req *menu.MaxSortReq) (res *menu.MaxSortRes, err error)
NameUnique(ctx context.Context, req *menu.NameUniqueReq) (res *menu.NameUniqueRes, err error)
CodeUnique(ctx context.Context, req *menu.CodeUniqueReq) (res *menu.CodeUniqueRes, err error)
Delete(ctx context.Context, req *menu.DeleteReq) (err error)
Edit(ctx context.Context, req *menu.EditReq) (err error)
View(ctx context.Context, req *menu.ViewReq) (res *menu.ViewRes, err error)
List(ctx context.Context, req *menu.ListReq) (lists []map[string]interface{}, err error)
GetMenuList(ctx context.Context, memberId int64) (res *role.DynamicRes, err error)
LoginPermissions(ctx context.Context, memberId int64) (lists adminin.MemberLoginPermissions, err error)
}
IAdminNotice interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
Delete(ctx context.Context, in adminin.NoticeDeleteInp) (err error)
Edit(ctx context.Context, in adminin.NoticeEditInp) (err error)
Status(ctx context.Context, in adminin.NoticeStatusInp) (err error)
MaxSort(ctx context.Context, in adminin.NoticeMaxSortInp) (res *adminin.NoticeMaxSortModel, err error)
View(ctx context.Context, in adminin.NoticeViewInp) (res *adminin.NoticeViewModel, err error)
List(ctx context.Context, in adminin.NoticeListInp) (list []*adminin.NoticeListModel, totalCount int, err error)
PullMessages(ctx context.Context, in adminin.PullMessagesInp) (res *adminin.PullMessagesModel, err error)
UnreadCount(ctx context.Context, in adminin.NoticeUnreadCountInp) (res *adminin.NoticeUnreadCountModel, err error)
UpRead(ctx context.Context, in adminin.NoticeUpReadInp) (err error)
ReadAll(ctx context.Context, in adminin.NoticeReadAllInp) (err error)
MessageList(ctx context.Context, in adminin.NoticeMessageListInp) (list []*adminin.NoticeMessageListModel, totalCount int, err error)
}
IAdminSite interface {
Register(ctx context.Context, in adminin.RegisterInp) (err error)
AccountLogin(ctx context.Context, in adminin.AccountLoginInp) (res *adminin.LoginModel, err error)
MobileLogin(ctx context.Context, in adminin.MobileLoginInp) (res *adminin.LoginModel, err error)
}
IAdminCash interface {
View(ctx context.Context, in adminin.CashViewInp) (res *adminin.CashViewModel, err error)
List(ctx context.Context, in adminin.CashListInp) (list []*adminin.CashListModel, totalCount int, err error)
Apply(ctx context.Context, in adminin.CashApplyInp) (err error)
Payment(ctx context.Context, in adminin.CashPaymentInp) (err error)
}
IAdminCreditsLog interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
SaveBalance(ctx context.Context, in adminin.CreditsLogSaveBalanceInp) (res *adminin.CreditsLogSaveBalanceModel, err error)
@ -26,8 +88,32 @@ type (
List(ctx context.Context, in adminin.CreditsLogListInp) (list []*adminin.CreditsLogListModel, totalCount int, err error)
Export(ctx context.Context, in adminin.CreditsLogListInp) (err error)
}
IAdminMemberPost interface {
UpdatePostIds(ctx context.Context, memberId int64, postIds []int64) (err error)
IAdminDept interface {
Delete(ctx context.Context, in adminin.DeptDeleteInp) (err error)
Edit(ctx context.Context, in adminin.DeptEditInp) (err error)
Status(ctx context.Context, in adminin.DeptStatusInp) (err error)
MaxSort(ctx context.Context, in adminin.DeptMaxSortInp) (res *adminin.DeptMaxSortModel, err error)
View(ctx context.Context, in adminin.DeptViewInp) (res *adminin.DeptViewModel, err error)
Option(ctx context.Context, in adminin.DeptOptionInp) (res *adminin.DeptOptionModel, totalCount int, err error)
List(ctx context.Context, in adminin.DeptListInp) (res *adminin.DeptListModel, err error)
GetName(ctx context.Context, id int64) (name string, err error)
}
IAdminMonitor interface {
StartMonitor(ctx context.Context)
GetMeta(ctx context.Context) *model.MonitorData
}
IAdminOrder interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
AcceptRefund(ctx context.Context, in adminin.OrderAcceptRefundInp) (err error)
ApplyRefund(ctx context.Context, in adminin.OrderApplyRefundInp) (err error)
PayNotify(ctx context.Context, in payin.NotifyCallFuncInp) (err error)
Create(ctx context.Context, in adminin.OrderCreateInp) (res *adminin.OrderCreateModel, err error)
List(ctx context.Context, in adminin.OrderListInp) (list []*adminin.OrderListModel, totalCount int, err error)
Export(ctx context.Context, in adminin.OrderListInp) (err error)
Edit(ctx context.Context, in adminin.OrderEditInp) (err error)
Delete(ctx context.Context, in adminin.OrderDeleteInp) (err error)
View(ctx context.Context, in adminin.OrderViewInp) (res *adminin.OrderViewModel, err error)
Status(ctx context.Context, in adminin.OrderStatusInp) (err error)
}
IAdminPost interface {
Delete(ctx context.Context, in adminin.PostDeleteInp) (err error)
@ -52,109 +138,34 @@ type (
DataScopeSelect() (res form.Selects)
DataScopeEdit(ctx context.Context, in *adminin.DataScopeEditInp) (err error)
}
IAdminCash interface {
View(ctx context.Context, in adminin.CashViewInp) (res *adminin.CashViewModel, err error)
List(ctx context.Context, in adminin.CashListInp) (list []*adminin.CashListModel, totalCount int, err error)
Apply(ctx context.Context, in adminin.CashApplyInp) (err error)
Payment(ctx context.Context, in adminin.CashPaymentInp) (err error)
}
IAdminMember interface {
AddBalance(ctx context.Context, in adminin.MemberAddBalanceInp) (err error)
AddIntegral(ctx context.Context, in adminin.MemberAddIntegralInp) (err error)
UpdateCash(ctx context.Context, in adminin.MemberUpdateCashInp) (err error)
UpdateEmail(ctx context.Context, in adminin.MemberUpdateEmailInp) (err error)
UpdateMobile(ctx context.Context, in adminin.MemberUpdateMobileInp) (err error)
UpdateProfile(ctx context.Context, in adminin.MemberUpdateProfileInp) (err error)
UpdatePwd(ctx context.Context, in adminin.MemberUpdatePwdInp) (err error)
ResetPwd(ctx context.Context, in adminin.MemberResetPwdInp) (err error)
VerifyUnique(ctx context.Context, in adminin.VerifyUniqueInp) (err error)
Delete(ctx context.Context, in adminin.MemberDeleteInp) (err error)
Edit(ctx context.Context, in adminin.MemberEditInp) (err error)
View(ctx context.Context, in adminin.MemberViewInp) (res *adminin.MemberViewModel, err error)
List(ctx context.Context, in adminin.MemberListInp) (list []*adminin.MemberListModel, totalCount int, err error)
Status(ctx context.Context, in adminin.MemberStatusInp) (err error)
GenTree(ctx context.Context, pid int64) (level int, newTree string, err error)
LoginMemberInfo(ctx context.Context) (res *adminin.LoginMemberInfoModel, err error)
MemberLoginStat(ctx context.Context, in adminin.MemberLoginStatInp) (res *adminin.MemberLoginStatModel, err error)
GetIdByCode(ctx context.Context, in adminin.GetIdByCodeInp) (res *adminin.GetIdByCodeModel, err error)
Select(ctx context.Context, in adminin.MemberSelectInp) (res []*adminin.MemberSelectModel, err error)
VerifySuperId(ctx context.Context, verifyId int64) bool
FilterAuthModel(ctx context.Context, memberId int64) *gdb.Model
}
IAdminMenu interface {
MaxSort(ctx context.Context, req *menu.MaxSortReq) (res *menu.MaxSortRes, err error)
NameUnique(ctx context.Context, req *menu.NameUniqueReq) (res *menu.NameUniqueRes, err error)
CodeUnique(ctx context.Context, req *menu.CodeUniqueReq) (res *menu.CodeUniqueRes, err error)
Delete(ctx context.Context, req *menu.DeleteReq) (err error)
Edit(ctx context.Context, req *menu.EditReq) (err error)
View(ctx context.Context, req *menu.ViewReq) (res *menu.ViewRes, err error)
List(ctx context.Context, req *menu.ListReq) (lists []map[string]interface{}, err error)
GetMenuList(ctx context.Context, memberId int64) (res *role.DynamicRes, err error)
LoginPermissions(ctx context.Context, memberId int64) (lists adminin.MemberLoginPermissions, err error)
}
IAdminMonitor interface {
StartMonitor(ctx context.Context)
GetMeta(ctx context.Context) *model.MonitorData
}
IAdminNotice interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
Delete(ctx context.Context, in adminin.NoticeDeleteInp) (err error)
Edit(ctx context.Context, in adminin.NoticeEditInp) (err error)
Status(ctx context.Context, in adminin.NoticeStatusInp) (err error)
MaxSort(ctx context.Context, in adminin.NoticeMaxSortInp) (res *adminin.NoticeMaxSortModel, err error)
View(ctx context.Context, in adminin.NoticeViewInp) (res *adminin.NoticeViewModel, err error)
List(ctx context.Context, in adminin.NoticeListInp) (list []*adminin.NoticeListModel, totalCount int, err error)
PullMessages(ctx context.Context, in adminin.PullMessagesInp) (res *adminin.PullMessagesModel, err error)
UnreadCount(ctx context.Context, in adminin.NoticeUnreadCountInp) (res *adminin.NoticeUnreadCountModel, err error)
UpRead(ctx context.Context, in adminin.NoticeUpReadInp) (err error)
ReadAll(ctx context.Context, in adminin.NoticeReadAllInp) (err error)
MessageList(ctx context.Context, in adminin.NoticeMessageListInp) (list []*adminin.NoticeMessageListModel, totalCount int, err error)
}
IAdminOrder interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
AcceptRefund(ctx context.Context, in adminin.OrderAcceptRefundInp) (err error)
ApplyRefund(ctx context.Context, in adminin.OrderApplyRefundInp) (err error)
PayNotify(ctx context.Context, in payin.NotifyCallFuncInp) (err error)
Create(ctx context.Context, in adminin.OrderCreateInp) (res *adminin.OrderCreateModel, err error)
List(ctx context.Context, in adminin.OrderListInp) (list []*adminin.OrderListModel, totalCount int, err error)
Export(ctx context.Context, in adminin.OrderListInp) (err error)
Edit(ctx context.Context, in adminin.OrderEditInp) (err error)
Delete(ctx context.Context, in adminin.OrderDeleteInp) (err error)
View(ctx context.Context, in adminin.OrderViewInp) (res *adminin.OrderViewModel, err error)
Status(ctx context.Context, in adminin.OrderStatusInp) (err error)
}
IAdminSite interface {
Register(ctx context.Context, in adminin.RegisterInp) (err error)
AccountLogin(ctx context.Context, in adminin.AccountLoginInp) (res *adminin.LoginModel, err error)
MobileLogin(ctx context.Context, in adminin.MobileLoginInp) (res *adminin.LoginModel, err error)
}
IAdminDept interface {
Delete(ctx context.Context, in adminin.DeptDeleteInp) (err error)
Edit(ctx context.Context, in adminin.DeptEditInp) (err error)
Status(ctx context.Context, in adminin.DeptStatusInp) (err error)
MaxSort(ctx context.Context, in adminin.DeptMaxSortInp) (res *adminin.DeptMaxSortModel, err error)
View(ctx context.Context, in adminin.DeptViewInp) (res *adminin.DeptViewModel, err error)
Option(ctx context.Context, in adminin.DeptOptionInp) (res *adminin.DeptOptionModel, totalCount int, err error)
List(ctx context.Context, in adminin.DeptListInp) (res *adminin.DeptListModel, err error)
GetName(ctx context.Context, id int64) (name string, err error)
}
)
var (
localAdminSite IAdminSite
localAdminCash IAdminCash
localAdminCreditsLog IAdminCreditsLog
localAdminMemberPost IAdminMemberPost
localAdminDept IAdminDept
localAdminMonitor IAdminMonitor
localAdminOrder IAdminOrder
localAdminPost IAdminPost
localAdminRole IAdminRole
localAdminDept IAdminDept
localAdminMember IAdminMember
localAdminMemberPost IAdminMemberPost
localAdminMenu IAdminMenu
localAdminMonitor IAdminMonitor
localAdminNotice IAdminNotice
localAdminOrder IAdminOrder
localAdminSite IAdminSite
)
func AdminSite() IAdminSite {
if localAdminSite == nil {
panic("implement not found for interface IAdminSite, forgot register?")
}
return localAdminSite
}
func RegisterAdminSite(i IAdminSite) {
localAdminSite = i
}
func AdminCash() IAdminCash {
if localAdminCash == nil {
panic("implement not found for interface IAdminCash, forgot register?")
@ -177,15 +188,37 @@ func RegisterAdminCreditsLog(i IAdminCreditsLog) {
localAdminCreditsLog = i
}
func AdminMemberPost() IAdminMemberPost {
if localAdminMemberPost == nil {
panic("implement not found for interface IAdminMemberPost, forgot register?")
func AdminDept() IAdminDept {
if localAdminDept == nil {
panic("implement not found for interface IAdminDept, forgot register?")
}
return localAdminMemberPost
return localAdminDept
}
func RegisterAdminMemberPost(i IAdminMemberPost) {
localAdminMemberPost = i
func RegisterAdminDept(i IAdminDept) {
localAdminDept = i
}
func AdminMonitor() IAdminMonitor {
if localAdminMonitor == nil {
panic("implement not found for interface IAdminMonitor, forgot register?")
}
return localAdminMonitor
}
func RegisterAdminMonitor(i IAdminMonitor) {
localAdminMonitor = i
}
func AdminOrder() IAdminOrder {
if localAdminOrder == nil {
panic("implement not found for interface IAdminOrder, forgot register?")
}
return localAdminOrder
}
func RegisterAdminOrder(i IAdminOrder) {
localAdminOrder = i
}
func AdminPost() IAdminPost {
@ -210,17 +243,6 @@ func RegisterAdminRole(i IAdminRole) {
localAdminRole = i
}
func AdminDept() IAdminDept {
if localAdminDept == nil {
panic("implement not found for interface IAdminDept, forgot register?")
}
return localAdminDept
}
func RegisterAdminDept(i IAdminDept) {
localAdminDept = i
}
func AdminMember() IAdminMember {
if localAdminMember == nil {
panic("implement not found for interface IAdminMember, forgot register?")
@ -232,6 +254,17 @@ func RegisterAdminMember(i IAdminMember) {
localAdminMember = i
}
func AdminMemberPost() IAdminMemberPost {
if localAdminMemberPost == nil {
panic("implement not found for interface IAdminMemberPost, forgot register?")
}
return localAdminMemberPost
}
func RegisterAdminMemberPost(i IAdminMemberPost) {
localAdminMemberPost = i
}
func AdminMenu() IAdminMenu {
if localAdminMenu == nil {
panic("implement not found for interface IAdminMenu, forgot register?")
@ -243,17 +276,6 @@ func RegisterAdminMenu(i IAdminMenu) {
localAdminMenu = i
}
func AdminMonitor() IAdminMonitor {
if localAdminMonitor == nil {
panic("implement not found for interface IAdminMonitor, forgot register?")
}
return localAdminMonitor
}
func RegisterAdminMonitor(i IAdminMonitor) {
localAdminMonitor = i
}
func AdminNotice() IAdminNotice {
if localAdminNotice == nil {
panic("implement not found for interface IAdminNotice, forgot register?")
@ -264,25 +286,3 @@ func AdminNotice() IAdminNotice {
func RegisterAdminNotice(i IAdminNotice) {
localAdminNotice = i
}
func AdminOrder() IAdminOrder {
if localAdminOrder == nil {
panic("implement not found for interface IAdminOrder, forgot register?")
}
return localAdminOrder
}
func RegisterAdminOrder(i IAdminOrder) {
localAdminOrder = i
}
func AdminSite() IAdminSite {
if localAdminSite == nil {
panic("implement not found for interface IAdminSite, forgot register?")
}
return localAdminSite
}
func RegisterAdminSite(i IAdminSite) {
localAdminSite = i
}

View File

@ -7,7 +7,6 @@ package service
import (
"context"
"hotgo/internal/model"
"hotgo/internal/model/input/commonin"
"hotgo/internal/model/input/sysin"
@ -16,15 +15,8 @@ import (
type (
ICommonUpload interface {
UploadFile(ctx context.Context, file *ghttp.UploadFile) (result *sysin.AttachmentListModel, err error)
UploadImage(ctx context.Context, file *ghttp.UploadFile) (result *sysin.AttachmentListModel, err error)
UploadLocal(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error)
UploadUCloud(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error)
UploadCOS(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error)
UploadOSS(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error)
UploadQiNiu(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error)
LastUrl(ctx context.Context, conf *model.UploadConfig, fullPath, drive string) string
HasFile(ctx context.Context, md5 string) (res *sysin.AttachmentListModel, err error)
UploadFile(ctx context.Context, file *ghttp.UploadFile) (res *sysin.AttachmentListModel, err error)
UploadImage(ctx context.Context, file *ghttp.UploadFile) (res *sysin.AttachmentListModel, err error)
}
ICommonWechat interface {
Authorize(ctx context.Context, in commonin.WechatAuthorizeInp) (res *commonin.WechatAuthorizeModel, err error)

View File

@ -17,11 +17,71 @@ import (
)
type (
ISysDictData interface {
Delete(ctx context.Context, in sysin.DictDataDeleteInp) error
Edit(ctx context.Context, in sysin.DictDataEditInp) (err error)
List(ctx context.Context, in sysin.DictDataListInp) (list []*sysin.DictDataListModel, totalCount int, err error)
Select(ctx context.Context, in sysin.DataSelectInp) (list sysin.DataSelectModel, err error)
ISysSmsLog interface {
Delete(ctx context.Context, in sysin.SmsLogDeleteInp) (err error)
Edit(ctx context.Context, in sysin.SmsLogEditInp) (err error)
Status(ctx context.Context, in sysin.SmsLogStatusInp) (err error)
MaxSort(ctx context.Context, in sysin.SmsLogMaxSortInp) (res *sysin.SmsLogMaxSortModel, err error)
View(ctx context.Context, in sysin.SmsLogViewInp) (res *sysin.SmsLogViewModel, err error)
List(ctx context.Context, in sysin.SmsLogListInp) (list []*sysin.SmsLogListModel, totalCount int, err error)
SendCode(ctx context.Context, in sysin.SendCodeInp) (err error)
GetTemplate(ctx context.Context, template string, config *model.SmsConfig) (val string, err error)
AllowSend(ctx context.Context, models *entity.SysSmsLog, config *model.SmsConfig) (err error)
VerifyCode(ctx context.Context, in sysin.VerifyCodeInp) (err error)
}
ISysServeLog interface {
Model(ctx context.Context) *gdb.Model
List(ctx context.Context, in sysin.ServeLogListInp) (list []*sysin.ServeLogListModel, totalCount int, err error)
Export(ctx context.Context, in sysin.ServeLogListInp) (err error)
Delete(ctx context.Context, in sysin.ServeLogDeleteInp) (err error)
View(ctx context.Context, in sysin.ServeLogViewInp) (res *sysin.ServeLogViewModel, err error)
RealWrite(ctx context.Context, models entity.SysServeLog) (err error)
}
ISysAddons interface {
List(ctx context.Context, in sysin.AddonsListInp) (list []*sysin.AddonsListModel, totalCount int, err error)
Selects(ctx context.Context, in sysin.AddonsSelectsInp) (res *sysin.AddonsSelectsModel, err error)
Build(ctx context.Context, in sysin.AddonsBuildInp) (err error)
Install(ctx context.Context, in sysin.AddonsInstallInp) (err error)
Upgrade(ctx context.Context, in sysin.AddonsUpgradeInp) (err error)
UnInstall(ctx context.Context, in sysin.AddonsUnInstallInp) (err error)
}
ISysCron interface {
StartCron(ctx context.Context)
Delete(ctx context.Context, in sysin.CronDeleteInp) (err error)
Edit(ctx context.Context, in sysin.CronEditInp) (err error)
Status(ctx context.Context, in sysin.CronStatusInp) (err error)
MaxSort(ctx context.Context, in sysin.CronMaxSortInp) (res *sysin.CronMaxSortModel, err error)
View(ctx context.Context, in sysin.CronViewInp) (res *sysin.CronViewModel, err error)
List(ctx context.Context, in sysin.CronListInp) (list []*sysin.CronListModel, totalCount int, err error)
OnlineExec(ctx context.Context, in sysin.OnlineExecInp) (err error)
}
ISysCurdDemo interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
List(ctx context.Context, in sysin.CurdDemoListInp) (list []*sysin.CurdDemoListModel, totalCount int, err error)
Export(ctx context.Context, in sysin.CurdDemoListInp) (err error)
Edit(ctx context.Context, in sysin.CurdDemoEditInp) (err error)
Delete(ctx context.Context, in sysin.CurdDemoDeleteInp) (err error)
MaxSort(ctx context.Context, in sysin.CurdDemoMaxSortInp) (res *sysin.CurdDemoMaxSortModel, err error)
View(ctx context.Context, in sysin.CurdDemoViewInp) (res *sysin.CurdDemoViewModel, err error)
Status(ctx context.Context, in sysin.CurdDemoStatusInp) (err error)
Switch(ctx context.Context, in sysin.CurdDemoSwitchInp) (err error)
}
ISysDictType interface {
Tree(ctx context.Context) (list []*sysin.DictTypeTree, err error)
Delete(ctx context.Context, in sysin.DictTypeDeleteInp) (err error)
Edit(ctx context.Context, in sysin.DictTypeEditInp) (err error)
TreeSelect(ctx context.Context, in sysin.DictTreeSelectInp) (list []*sysin.DictTypeTree, err error)
}
ISysEmsLog interface {
Delete(ctx context.Context, in sysin.EmsLogDeleteInp) (err error)
Edit(ctx context.Context, in sysin.EmsLogEditInp) (err error)
Status(ctx context.Context, in sysin.EmsLogStatusInp) (err error)
View(ctx context.Context, in sysin.EmsLogViewInp) (res *sysin.EmsLogViewModel, err error)
List(ctx context.Context, in sysin.EmsLogListInp) (list []*sysin.EmsLogListModel, totalCount int, err error)
Send(ctx context.Context, in sysin.SendEmsInp) (err error)
GetTemplate(ctx context.Context, template string, config *model.EmailConfig) (val string, err error)
AllowSend(ctx context.Context, models *entity.SysEmsLog, config *model.EmailConfig) (err error)
VerifyCode(ctx context.Context, in sysin.VerifyEmsCodeInp) (err error)
}
ISysGenCodes interface {
Delete(ctx context.Context, in sysin.GenCodesDeleteInp) (err error)
@ -37,32 +97,11 @@ type (
Preview(ctx context.Context, in sysin.GenCodesPreviewInp) (res *sysin.GenCodesPreviewModel, err error)
Build(ctx context.Context, in sysin.GenCodesBuildInp) (err error)
}
ISysLog interface {
Export(ctx context.Context, in sysin.LogListInp) (err error)
RealWrite(ctx context.Context, log entity.SysLog) (err error)
AutoLog(ctx context.Context) error
AnalysisLog(ctx context.Context) entity.SysLog
View(ctx context.Context, in sysin.LogViewInp) (res *sysin.LogViewModel, err error)
Delete(ctx context.Context, in sysin.LogDeleteInp) (err error)
List(ctx context.Context, in sysin.LogListInp) (list []*sysin.LogListModel, totalCount int, err error)
}
ISysServeLog interface {
Model(ctx context.Context) *gdb.Model
List(ctx context.Context, in sysin.ServeLogListInp) (list []*sysin.ServeLogListModel, totalCount int, err error)
Export(ctx context.Context, in sysin.ServeLogListInp) (err error)
Delete(ctx context.Context, in sysin.ServeLogDeleteInp) (err error)
View(ctx context.Context, in sysin.ServeLogViewInp) (res *sysin.ServeLogViewModel, err error)
RealWrite(ctx context.Context, models entity.SysServeLog) (err error)
}
ISysCron interface {
StartCron(ctx context.Context)
Delete(ctx context.Context, in sysin.CronDeleteInp) (err error)
Edit(ctx context.Context, in sysin.CronEditInp) (err error)
Status(ctx context.Context, in sysin.CronStatusInp) (err error)
MaxSort(ctx context.Context, in sysin.CronMaxSortInp) (res *sysin.CronMaxSortModel, err error)
View(ctx context.Context, in sysin.CronViewInp) (res *sysin.CronViewModel, err error)
List(ctx context.Context, in sysin.CronListInp) (list []*sysin.CronListModel, totalCount int, err error)
OnlineExec(ctx context.Context, in sysin.OnlineExecInp) (err error)
ISysAttachment interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
Delete(ctx context.Context, in sysin.AttachmentDeleteInp) (err error)
View(ctx context.Context, in sysin.AttachmentViewInp) (res *sysin.AttachmentViewModel, err error)
List(ctx context.Context, in sysin.AttachmentListInp) (list []*sysin.AttachmentListModel, totalCount int, err error)
}
ISysBlacklist interface {
Delete(ctx context.Context, in sysin.BlacklistDeleteInp) (err error)
@ -95,32 +134,35 @@ type (
ConversionType(ctx context.Context, models *entity.SysConfig) (value interface{}, err error)
UpdateConfigByGroup(ctx context.Context, in sysin.UpdateConfigInp) (err error)
}
ISysCurdDemo interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
List(ctx context.Context, in sysin.CurdDemoListInp) (list []*sysin.CurdDemoListModel, totalCount int, err error)
Export(ctx context.Context, in sysin.CurdDemoListInp) (err error)
Edit(ctx context.Context, in sysin.CurdDemoEditInp) (err error)
Delete(ctx context.Context, in sysin.CurdDemoDeleteInp) (err error)
MaxSort(ctx context.Context, in sysin.CurdDemoMaxSortInp) (res *sysin.CurdDemoMaxSortModel, err error)
View(ctx context.Context, in sysin.CurdDemoViewInp) (res *sysin.CurdDemoViewModel, err error)
Status(ctx context.Context, in sysin.CurdDemoStatusInp) (err error)
Switch(ctx context.Context, in sysin.CurdDemoSwitchInp) (err error)
ISysLog interface {
Export(ctx context.Context, in sysin.LogListInp) (err error)
RealWrite(ctx context.Context, log entity.SysLog) (err error)
AutoLog(ctx context.Context) error
AnalysisLog(ctx context.Context) entity.SysLog
View(ctx context.Context, in sysin.LogViewInp) (res *sysin.LogViewModel, err error)
Delete(ctx context.Context, in sysin.LogDeleteInp) (err error)
List(ctx context.Context, in sysin.LogListInp) (list []*sysin.LogListModel, totalCount int, err error)
}
ISysDictType interface {
Tree(ctx context.Context) (list []*sysin.DictTypeTree, err error)
Delete(ctx context.Context, in sysin.DictTypeDeleteInp) (err error)
Edit(ctx context.Context, in sysin.DictTypeEditInp) (err error)
TreeSelect(ctx context.Context, in sysin.DictTreeSelectInp) (list []*sysin.DictTypeTree, err error)
ISysLoginLog interface {
Model(ctx context.Context) *gdb.Model
List(ctx context.Context, in sysin.LoginLogListInp) (list []*sysin.LoginLogListModel, totalCount int, err error)
Export(ctx context.Context, in sysin.LoginLogListInp) (err error)
Delete(ctx context.Context, in sysin.LoginLogDeleteInp) (err error)
View(ctx context.Context, in sysin.LoginLogViewInp) (res *sysin.LoginLogViewModel, err error)
Push(ctx context.Context, in sysin.LoginLogPushInp)
RealWrite(ctx context.Context, models entity.SysLoginLog) (err error)
}
ISysAttachment interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
Delete(ctx context.Context, in sysin.AttachmentDeleteInp) (err error)
Edit(ctx context.Context, in sysin.AttachmentEditInp) (err error)
Status(ctx context.Context, in sysin.AttachmentStatusInp) (err error)
MaxSort(ctx context.Context, in sysin.AttachmentMaxSortInp) (res *sysin.AttachmentMaxSortModel, err error)
View(ctx context.Context, in sysin.AttachmentViewInp) (res *sysin.AttachmentViewModel, err error)
List(ctx context.Context, in sysin.AttachmentListInp) (list []*sysin.AttachmentListModel, totalCount int, err error)
Add(ctx context.Context, meta *sysin.UploadFileMeta, fullPath, drive string) (models *entity.SysAttachment, err error)
ISysProvinces interface {
Tree(ctx context.Context) (list []g.Map, err error)
Delete(ctx context.Context, in sysin.ProvincesDeleteInp) (err error)
Edit(ctx context.Context, in sysin.ProvincesEditInp) (err error)
Status(ctx context.Context, in sysin.ProvincesStatusInp) (err error)
MaxSort(ctx context.Context, in sysin.ProvincesMaxSortInp) (res *sysin.ProvincesMaxSortModel, err error)
View(ctx context.Context, in sysin.ProvincesViewInp) (res *sysin.ProvincesViewModel, err error)
List(ctx context.Context, in sysin.ProvincesListInp) (list []*sysin.ProvincesListModel, totalCount int, err error)
ChildrenList(ctx context.Context, in sysin.ProvincesChildrenListInp) (list []*sysin.ProvincesChildrenListModel, totalCount int, err error)
UniqueId(ctx context.Context, in sysin.ProvincesUniqueIdInp) (res *sysin.ProvincesUniqueIdModel, err error)
Select(ctx context.Context, in sysin.ProvincesSelectInp) (res *sysin.ProvincesSelectModel, err error)
}
ISysAddonsConfig interface {
GetConfigByGroup(ctx context.Context, in sysin.GetAddonsConfigInp) (res *sysin.GetAddonsConfigModel, err error)
@ -136,122 +178,54 @@ type (
List(ctx context.Context, in sysin.CronGroupListInp) (list []*sysin.CronGroupListModel, totalCount int, err error)
Select(ctx context.Context, in sysin.CronGroupSelectInp) (res *sysin.CronGroupSelectModel, err error)
}
ISysEmsLog interface {
Delete(ctx context.Context, in sysin.EmsLogDeleteInp) (err error)
Edit(ctx context.Context, in sysin.EmsLogEditInp) (err error)
Status(ctx context.Context, in sysin.EmsLogStatusInp) (err error)
View(ctx context.Context, in sysin.EmsLogViewInp) (res *sysin.EmsLogViewModel, err error)
List(ctx context.Context, in sysin.EmsLogListInp) (list []*sysin.EmsLogListModel, totalCount int, err error)
Send(ctx context.Context, in sysin.SendEmsInp) (err error)
GetTemplate(ctx context.Context, template string, config *model.EmailConfig) (val string, err error)
AllowSend(ctx context.Context, models *entity.SysEmsLog, config *model.EmailConfig) (err error)
VerifyCode(ctx context.Context, in sysin.VerifyEmsCodeInp) (err error)
}
ISysProvinces interface {
Tree(ctx context.Context) (list []g.Map, err error)
Delete(ctx context.Context, in sysin.ProvincesDeleteInp) (err error)
Edit(ctx context.Context, in sysin.ProvincesEditInp) (err error)
Status(ctx context.Context, in sysin.ProvincesStatusInp) (err error)
MaxSort(ctx context.Context, in sysin.ProvincesMaxSortInp) (res *sysin.ProvincesMaxSortModel, err error)
View(ctx context.Context, in sysin.ProvincesViewInp) (res *sysin.ProvincesViewModel, err error)
List(ctx context.Context, in sysin.ProvincesListInp) (list []*sysin.ProvincesListModel, totalCount int, err error)
ChildrenList(ctx context.Context, in sysin.ProvincesChildrenListInp) (list []*sysin.ProvincesChildrenListModel, totalCount int, err error)
UniqueId(ctx context.Context, in sysin.ProvincesUniqueIdInp) (res *sysin.ProvincesUniqueIdModel, err error)
Select(ctx context.Context, in sysin.ProvincesSelectInp) (res *sysin.ProvincesSelectModel, err error)
}
ISysAddons interface {
List(ctx context.Context, in sysin.AddonsListInp) (list []*sysin.AddonsListModel, totalCount int, err error)
Selects(ctx context.Context, in sysin.AddonsSelectsInp) (res *sysin.AddonsSelectsModel, err error)
Build(ctx context.Context, in sysin.AddonsBuildInp) (err error)
Install(ctx context.Context, in sysin.AddonsInstallInp) (err error)
Upgrade(ctx context.Context, in sysin.AddonsUpgradeInp) (err error)
UnInstall(ctx context.Context, in sysin.AddonsUnInstallInp) (err error)
}
ISysSmsLog interface {
Delete(ctx context.Context, in sysin.SmsLogDeleteInp) (err error)
Edit(ctx context.Context, in sysin.SmsLogEditInp) (err error)
Status(ctx context.Context, in sysin.SmsLogStatusInp) (err error)
MaxSort(ctx context.Context, in sysin.SmsLogMaxSortInp) (res *sysin.SmsLogMaxSortModel, err error)
View(ctx context.Context, in sysin.SmsLogViewInp) (res *sysin.SmsLogViewModel, err error)
List(ctx context.Context, in sysin.SmsLogListInp) (list []*sysin.SmsLogListModel, totalCount int, err error)
SendCode(ctx context.Context, in sysin.SendCodeInp) (err error)
GetTemplate(ctx context.Context, template string, config *model.SmsConfig) (val string, err error)
AllowSend(ctx context.Context, models *entity.SysSmsLog, config *model.SmsConfig) (err error)
VerifyCode(ctx context.Context, in sysin.VerifyCodeInp) (err error)
}
ISysLoginLog interface {
Model(ctx context.Context) *gdb.Model
List(ctx context.Context, in sysin.LoginLogListInp) (list []*sysin.LoginLogListModel, totalCount int, err error)
Export(ctx context.Context, in sysin.LoginLogListInp) (err error)
Delete(ctx context.Context, in sysin.LoginLogDeleteInp) (err error)
View(ctx context.Context, in sysin.LoginLogViewInp) (res *sysin.LoginLogViewModel, err error)
Push(ctx context.Context, in sysin.LoginLogPushInp)
RealWrite(ctx context.Context, models entity.SysLoginLog) (err error)
ISysDictData interface {
Delete(ctx context.Context, in sysin.DictDataDeleteInp) error
Edit(ctx context.Context, in sysin.DictDataEditInp) (err error)
List(ctx context.Context, in sysin.DictDataListInp) (list []*sysin.DictDataListModel, totalCount int, err error)
Select(ctx context.Context, in sysin.DataSelectInp) (list sysin.DataSelectModel, err error)
}
)
var (
localSysDictData ISysDictData
localSysGenCodes ISysGenCodes
localSysLog ISysLog
localSysServeLog ISysServeLog
localSysCron ISysCron
localSysCurdDemo ISysCurdDemo
localSysServeLog ISysServeLog
localSysAddons ISysAddons
localSysBlacklist ISysBlacklist
localSysConfig ISysConfig
localSysCurdDemo ISysCurdDemo
localSysDictType ISysDictType
localSysAttachment ISysAttachment
localSysAddonsConfig ISysAddonsConfig
localSysCronGroup ISysCronGroup
localSysEmsLog ISysEmsLog
localSysProvinces ISysProvinces
localSysAddons ISysAddons
localSysSmsLog ISysSmsLog
localSysGenCodes ISysGenCodes
localSysAttachment ISysAttachment
localSysCronGroup ISysCronGroup
localSysDictData ISysDictData
localSysLog ISysLog
localSysLoginLog ISysLoginLog
localSysProvinces ISysProvinces
localSysAddonsConfig ISysAddonsConfig
localSysSmsLog ISysSmsLog
)
func SysProvinces() ISysProvinces {
if localSysProvinces == nil {
panic("implement not found for interface ISysProvinces, forgot register?")
func SysConfig() ISysConfig {
if localSysConfig == nil {
panic("implement not found for interface ISysConfig, forgot register?")
}
return localSysProvinces
return localSysConfig
}
func RegisterSysProvinces(i ISysProvinces) {
localSysProvinces = i
func RegisterSysConfig(i ISysConfig) {
localSysConfig = i
}
func SysAddons() ISysAddons {
if localSysAddons == nil {
panic("implement not found for interface ISysAddons, forgot register?")
func SysDictType() ISysDictType {
if localSysDictType == nil {
panic("implement not found for interface ISysDictType, forgot register?")
}
return localSysAddons
return localSysDictType
}
func RegisterSysAddons(i ISysAddons) {
localSysAddons = i
}
func SysAddonsConfig() ISysAddonsConfig {
if localSysAddonsConfig == nil {
panic("implement not found for interface ISysAddonsConfig, forgot register?")
}
return localSysAddonsConfig
}
func RegisterSysAddonsConfig(i ISysAddonsConfig) {
localSysAddonsConfig = i
}
func SysCronGroup() ISysCronGroup {
if localSysCronGroup == nil {
panic("implement not found for interface ISysCronGroup, forgot register?")
}
return localSysCronGroup
}
func RegisterSysCronGroup(i ISysCronGroup) {
localSysCronGroup = i
func RegisterSysDictType(i ISysDictType) {
localSysDictType = i
}
func SysEmsLog() ISysEmsLog {
@ -265,61 +239,6 @@ func RegisterSysEmsLog(i ISysEmsLog) {
localSysEmsLog = i
}
func SysLoginLog() ISysLoginLog {
if localSysLoginLog == nil {
panic("implement not found for interface ISysLoginLog, forgot register?")
}
return localSysLoginLog
}
func RegisterSysLoginLog(i ISysLoginLog) {
localSysLoginLog = i
}
func SysSmsLog() ISysSmsLog {
if localSysSmsLog == nil {
panic("implement not found for interface ISysSmsLog, forgot register?")
}
return localSysSmsLog
}
func RegisterSysSmsLog(i ISysSmsLog) {
localSysSmsLog = i
}
func SysServeLog() ISysServeLog {
if localSysServeLog == nil {
panic("implement not found for interface ISysServeLog, forgot register?")
}
return localSysServeLog
}
func RegisterSysServeLog(i ISysServeLog) {
localSysServeLog = i
}
func SysCron() ISysCron {
if localSysCron == nil {
panic("implement not found for interface ISysCron, forgot register?")
}
return localSysCron
}
func RegisterSysCron(i ISysCron) {
localSysCron = i
}
func SysDictData() ISysDictData {
if localSysDictData == nil {
panic("implement not found for interface ISysDictData, forgot register?")
}
return localSysDictData
}
func RegisterSysDictData(i ISysDictData) {
localSysDictData = i
}
func SysGenCodes() ISysGenCodes {
if localSysGenCodes == nil {
panic("implement not found for interface ISysGenCodes, forgot register?")
@ -331,28 +250,6 @@ func RegisterSysGenCodes(i ISysGenCodes) {
localSysGenCodes = i
}
func SysLog() ISysLog {
if localSysLog == nil {
panic("implement not found for interface ISysLog, forgot register?")
}
return localSysLog
}
func RegisterSysLog(i ISysLog) {
localSysLog = i
}
func SysDictType() ISysDictType {
if localSysDictType == nil {
panic("implement not found for interface ISysDictType, forgot register?")
}
return localSysDictType
}
func RegisterSysDictType(i ISysDictType) {
localSysDictType = i
}
func SysAttachment() ISysAttachment {
if localSysAttachment == nil {
panic("implement not found for interface ISysAttachment, forgot register?")
@ -375,15 +272,81 @@ func RegisterSysBlacklist(i ISysBlacklist) {
localSysBlacklist = i
}
func SysConfig() ISysConfig {
if localSysConfig == nil {
panic("implement not found for interface ISysConfig, forgot register?")
func SysDictData() ISysDictData {
if localSysDictData == nil {
panic("implement not found for interface ISysDictData, forgot register?")
}
return localSysConfig
return localSysDictData
}
func RegisterSysConfig(i ISysConfig) {
localSysConfig = i
func RegisterSysDictData(i ISysDictData) {
localSysDictData = i
}
func SysLog() ISysLog {
if localSysLog == nil {
panic("implement not found for interface ISysLog, forgot register?")
}
return localSysLog
}
func RegisterSysLog(i ISysLog) {
localSysLog = i
}
func SysLoginLog() ISysLoginLog {
if localSysLoginLog == nil {
panic("implement not found for interface ISysLoginLog, forgot register?")
}
return localSysLoginLog
}
func RegisterSysLoginLog(i ISysLoginLog) {
localSysLoginLog = i
}
func SysProvinces() ISysProvinces {
if localSysProvinces == nil {
panic("implement not found for interface ISysProvinces, forgot register?")
}
return localSysProvinces
}
func RegisterSysProvinces(i ISysProvinces) {
localSysProvinces = i
}
func SysAddonsConfig() ISysAddonsConfig {
if localSysAddonsConfig == nil {
panic("implement not found for interface ISysAddonsConfig, forgot register?")
}
return localSysAddonsConfig
}
func RegisterSysAddonsConfig(i ISysAddonsConfig) {
localSysAddonsConfig = i
}
func SysCronGroup() ISysCronGroup {
if localSysCronGroup == nil {
panic("implement not found for interface ISysCronGroup, forgot register?")
}
return localSysCronGroup
}
func RegisterSysCronGroup(i ISysCronGroup) {
localSysCronGroup = i
}
func SysSmsLog() ISysSmsLog {
if localSysSmsLog == nil {
panic("implement not found for interface ISysSmsLog, forgot register?")
}
return localSysSmsLog
}
func RegisterSysSmsLog(i ISysSmsLog) {
localSysSmsLog = i
}
func SysCurdDemo() ISysCurdDemo {
@ -396,3 +359,36 @@ func SysCurdDemo() ISysCurdDemo {
func RegisterSysCurdDemo(i ISysCurdDemo) {
localSysCurdDemo = i
}
func SysServeLog() ISysServeLog {
if localSysServeLog == nil {
panic("implement not found for interface ISysServeLog, forgot register?")
}
return localSysServeLog
}
func RegisterSysServeLog(i ISysServeLog) {
localSysServeLog = i
}
func SysAddons() ISysAddons {
if localSysAddons == nil {
panic("implement not found for interface ISysAddons, forgot register?")
}
return localSysAddons
}
func RegisterSysAddons(i ISysAddons) {
localSysAddons = i
}
func SysCron() ISysCron {
if localSysCron == nil {
panic("implement not found for interface ISysCron, forgot register?")
}
return localSysCron
}
func RegisterSysCron(i ISysCron) {
localSysCron = i
}

View File

@ -28,21 +28,10 @@ type (
)
var (
localAuthClient IAuthClient
localCronClient ICronClient
localAuthClient IAuthClient
)
func CronClient() ICronClient {
if localCronClient == nil {
panic("implement not found for interface ICronClient, forgot register?")
}
return localCronClient
}
func RegisterCronClient(i ICronClient) {
localCronClient = i
}
func AuthClient() IAuthClient {
if localAuthClient == nil {
panic("implement not found for interface IAuthClient, forgot register?")
@ -53,3 +42,14 @@ func AuthClient() IAuthClient {
func RegisterAuthClient(i IAuthClient) {
localAuthClient = i
}
func CronClient() ICronClient {
if localCronClient == nil {
panic("implement not found for interface ICronClient, forgot register?")
}
return localCronClient
}
func RegisterCronClient(i ICronClient) {
localCronClient = i
}

View File

@ -289,7 +289,6 @@ func (manager *ClientManager) start() {
g.Log().Info(ctxManager, "websocket closeSignal quit..")
return
}
}
}

View File

@ -8,14 +8,14 @@ package genrouter
import (
"context"
"github.com/gogf/gf/v2/net/ghttp"
"hotgo/addons/@{.name}/global"
"hotgo/addons/hgexample/global"
"hotgo/internal/consts"
"hotgo/internal/library/addons"
"hotgo/internal/service"
)
var (
NoLogin []interface{} // 无需登录
NoLoginRouter []interface{} // 无需登录
LoginRequiredRouter []interface{} // 需要登录
)
@ -23,8 +23,8 @@ var (
func Register(ctx context.Context, group *ghttp.RouterGroup) {
prefix := addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name)
group.Group(prefix, func(group *ghttp.RouterGroup) {
if len(NoLogin) > 0 {
group.Bind(NoLogin...)
if len(NoLoginRouter) > 0 {
group.Bind(NoLoginRouter...)
}
group.Middleware(service.Middleware().AdminAuth)
if len(LoginRequiredRouter) > 0 {

View File

@ -117,7 +117,7 @@ func (in *@{.varName}StatusInp) Filter(ctx context.Context) (err error) {
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}

View File

@ -159,7 +159,7 @@ func (s *s@{.servFunName}) Switch(ctx context.Context, in @{.templateGroup}in.@{
// ...
}
if !validate.InSliceString(fields, in.Key) {
if !validate.InSlice(fields, in.Key) {
err = gerror.New("开关键名不在白名单")
return
}

View File

@ -9,41 +9,11 @@ import (
"crypto/rand"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/utility/convert"
r "math/rand"
"strings"
"time"
)
// SplitMemberIds 从截取字串符中读取用户ID
func SplitMemberIds(str, pos string) (memberIds []int64) {
receiver := strings.Split(strings.TrimSpace(str), pos)
if len(receiver) == 0 {
return memberIds
}
if len(receiver) == 1 && strings.TrimSpace(receiver[0]) == "" {
return memberIds
}
for _, memberId := range receiver {
memberIds = append(memberIds, gconv.Int64(strings.TrimSpace(memberId)))
}
return convert.UniqueSliceInt64(memberIds)
}
// GetMapKeysByString 获取map的所有key字串符类型
func GetMapKeysByString(m map[string]string) []string {
// 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率很高
j := 0
keys := make([]string, len(m))
for k := range m {
keys[j] = k
j++
}
return keys
}
// RandomCreateBytes 生成随机字串符
func RandomCreateBytes(n int, alphabets ...byte) []byte {
if len(alphabets) == 0 {
@ -51,13 +21,12 @@ func RandomCreateBytes(n int, alphabets ...byte) []byte {
}
var bytes = make([]byte, n)
var randBy bool
r.Seed(time.Now().UnixNano())
if num, err := rand.Read(bytes); num != n || err != nil {
randBy = true
}
for i, b := range bytes {
if randBy {
bytes[i] = alphabets[r.Intn(len(alphabets))]
bytes[i] = alphabets[r.New(r.NewSource(time.Now().UnixNano())).Intn(len(alphabets))]
} else {
bytes[i] = alphabets[b%byte(len(alphabets))]
}

View File

@ -17,23 +17,21 @@ var (
fieldTags = []string{"json"} // 实体字段名称映射
)
// UniqueSliceInt64 切片去重
func UniqueSliceInt64(languages []int64) []int64 {
result := make([]int64, 0, len(languages))
temp := map[int64]struct{}{}
for _, item := range languages {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
result = append(result, item)
}
// GetMapKeys 获取map的所有key
func GetMapKeys[K comparable](m map[K]any) []K {
j := 0
keys := make([]K, len(m))
for k := range m {
keys[j] = k
j++
}
return result
return keys
}
// UniqueSliceString 切片去重
func UniqueSliceString(languages []string) []string {
result := make([]string, 0, len(languages))
temp := map[string]struct{}{}
// UniqueSlice 切片去重
func UniqueSlice[K comparable](languages []K) []K {
result := make([]K, 0, len(languages))
temp := map[K]struct{}{}
for _, item := range languages {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
@ -121,19 +119,19 @@ func reflectTag(reflectType reflect.Type, filterTags []string, tags []string) ([
// reflectTagName 解析实体中的描述标签优先级description > dc > json > Name
func reflectTagName(field reflect.StructField, filterTags []string, isDef bool) string {
if validate.InSliceString(filterTags, "description") {
if validate.InSlice(filterTags, "description") {
if description, ok := field.Tag.Lookup("description"); ok && description != "" {
return description
}
}
if validate.InSliceString(filterTags, "dc") {
if validate.InSlice(filterTags, "dc") {
if dc, ok := field.Tag.Lookup("dc"); ok && dc != "" {
return dc
}
}
if validate.InSliceString(filterTags, "json") {
if validate.InSlice(filterTags, "json") {
if jsonName, ok := field.Tag.Lookup("json"); ok && jsonName != "" {
return jsonName
}

View File

@ -12,12 +12,6 @@ import (
"path/filepath"
)
const ( //文件大小单位
_ = iota
KB = 1 << (10 * iota)
MB
)
type fileInfo struct { //文件信息
name string
size int64

View File

@ -7,40 +7,67 @@ package format
import (
"fmt"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"strconv"
)
// Round2String 四舍五入保留小数默认2位
func Round2String(value float64, args ...interface{}) (v string) {
func Round2String(value float64, args ...interface{}) string {
var places = 2
if len(args) > 0 {
places = gconv.Int(args[0])
}
cDig := strconv.Itoa(places)
val := fmt.Sprintf("%0."+cDig+"f", value)
return val
return fmt.Sprintf("%0."+strconv.Itoa(places)+"f", value)
}
// Round2Float64 四舍五入保留小数默认2位
func Round2Float64(value float64, args ...interface{}) (v float64) {
func Round2Float64(value float64, args ...interface{}) float64 {
return gconv.Float64(Round2String(value, args...))
}
// FileSize 字节的单位转换 保留两位小数
func FileSize(fileSize int64) (size string) {
if fileSize < 1024 {
return fmt.Sprintf("%.2fB", float64(fileSize)/float64(1))
} else if fileSize < (1024 * 1024) {
return fmt.Sprintf("%.2fKB", float64(fileSize)/float64(1024))
} else if fileSize < (1024 * 1024 * 1024) {
return fmt.Sprintf("%.2fMB", float64(fileSize)/float64(1024*1024))
} else if fileSize < (1024 * 1024 * 1024 * 1024) {
return fmt.Sprintf("%.2fGB", float64(fileSize)/float64(1024*1024*1024))
} else if fileSize < (1024 * 1024 * 1024 * 1024 * 1024) {
return fmt.Sprintf("%.2fTB", float64(fileSize)/float64(1024*1024*1024*1024))
} else {
return fmt.Sprintf("%.2fEB", float64(fileSize)/float64(1024*1024*1024*1024*1024))
func FileSize(data int64) string {
var factor float64 = 1024
res := float64(data)
for _, unit := range []string{"", "K", "M", "G", "T", "P"} {
if res < factor {
return fmt.Sprintf("%.2f%sB", res, unit)
}
res /= factor
}
return fmt.Sprintf("%.2f%sB", res, "P")
}
// AgoTime 多久以前
func AgoTime(gt *gtime.Time) string {
if gt == nil {
return ""
}
n := gtime.Now().Timestamp()
t := gt.Timestamp()
var ys int64 = 31536000
var ds int64 = 86400
var hs int64 = 3600
var ms int64 = 60
var ss int64 = 1
var rs string
d := n - t
switch {
case d > ys:
rs = fmt.Sprintf("%d年前", int(d/ys))
case d > ds:
rs = fmt.Sprintf("%d天前", int(d/ds))
case d > hs:
rs = fmt.Sprintf("%d小时前", int(d/hs))
case d > ms:
rs = fmt.Sprintf("%d分钟前", int(d/ms))
case d > ss:
rs = fmt.Sprintf("%d秒前", int(d/ss))
default:
rs = "刚刚"
}
return rs
}

View File

@ -1,56 +0,0 @@
// Package signal
// @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 signal
import (
"sync"
)
type StopSignal int32
type exitWait struct {
mutex sync.Mutex
wg *sync.WaitGroup
deferFuns []func()
stopSignList []chan StopSignal
}
var exitWaitHandler *exitWait
func init() {
exitWaitHandler = &exitWait{
wg: &sync.WaitGroup{},
}
}
// ExitWaitFunDo 退出后等待处理完成
func ExitWaitFunDo(doFun func()) {
exitWaitHandler.wg.Add(1)
defer exitWaitHandler.wg.Done()
if doFun != nil {
doFun()
}
}
// AppDefer 应用退出后置操作
func AppDefer(deferFun ...func()) {
exitWaitHandler.mutex.Lock()
defer exitWaitHandler.mutex.Unlock()
for _, funcItem := range deferFun {
if funcItem != nil {
exitWaitHandler.deferFuns = append(exitWaitHandler.deferFuns, funcItem)
}
}
}
// ListenStop 订阅app退出信号
func ListenStop(stopSig chan StopSignal) {
exitWaitHandler.mutex.Lock()
defer exitWaitHandler.mutex.Unlock()
exitWaitHandler.stopSignList = append(exitWaitHandler.stopSignList, stopSig)
}

View File

@ -0,0 +1,51 @@
package simple
import (
"context"
"sync"
)
type EventFunc func(ctx context.Context, args ...interface{})
type sEvent struct {
sync.Mutex
list map[string][]EventFunc // 所有事件的列表
}
var event *sEvent
// InstanceEvent 事件实例
func InstanceEvent() *sEvent {
if event == nil {
event = &sEvent{
list: make(map[string][]EventFunc),
}
}
return event
}
// Register 往一个分组中注册事件
func (e *sEvent) Register(group string, callback EventFunc) {
e.Lock()
defer e.Unlock()
e.list[group] = append(e.list[group], callback)
}
// Call 回调一个分组的事件
func (e *sEvent) Call(group string, ctx context.Context, args ...interface{}) {
if events, ok := e.list[group]; ok {
for _, f := range events {
f(ctx, args...)
}
}
}
// Remove 移动一个分组的事件
func (e *sEvent) Remove(group string) {
delete(e.list, group)
}
// Clear 清空事件列表
func (e *sEvent) Clear() {
e.list = make(map[string][]EventFunc)
}

View File

@ -8,35 +8,40 @@ package useragent
import (
"fmt"
"github.com/gogf/gf/v2/text/gstr"
"hotgo/internal/consts"
"regexp"
"strings"
)
// GetOs 获取OS名称
func GetOs(userAgent string) string {
osName := "Unknown"
osName := consts.Unknown
if userAgent == "" {
return osName
}
strRe, _ := regexp.Compile(`(?i:\((.*?)\))`)
userAgent = strRe.FindString(userAgent)
var (
strRe, _ = regexp.Compile(`(?i:\((.*?)\))`)
levelNames = ":micromessenger:dart:Windows NT:Windows Mobile:Windows Phone:Windows Phone OS:Macintosh|Macintosh:Mac OS:CrOS|CrOS:iPhone OS:iPad|iPad:OS:Android:Linux:blackberry:hpwOS:Series:Symbian:PalmOS:SymbianOS:J2ME:Sailfish:Bada:MeeGo:webOS|hpwOS:Maemo:"
namesArr = strings.Split(strings.Trim(levelNames, ":"), ":")
regStrArr = make([]string, len(namesArr))
)
levelNames := ":micromessenger:dart:Windows NT:Windows Mobile:Windows Phone:Windows Phone OS:Macintosh|Macintosh:Mac OS:CrOS|CrOS:iPhone OS:iPad|iPad:OS:Android:Linux:blackberry:hpwOS:Series:Symbian:PalmOS:SymbianOS:J2ME:Sailfish:Bada:MeeGo:webOS|hpwOS:Maemo:"
var regStrArr []string
namesArr := strings.Split(strings.Trim(levelNames, ":"), ":")
for _, name := range namesArr {
regStrArr = append(regStrArr, fmt.Sprintf("(%s[\\s?\\/XxSs0-9_.]+)", name))
for k, name := range namesArr {
regStrArr[k] = fmt.Sprintf("(%s[\\s?\\/XxSs0-9_.]+)", name)
}
regexpStr := fmt.Sprintf("(?i:%s)", strings.Join(regStrArr, "|"))
nameRe, _ := regexp.Compile(regexpStr)
names := nameRe.FindAllString(userAgent, -1)
name := ""
userAgent = strRe.FindString(userAgent)
var (
nameRe, _ = regexp.Compile(fmt.Sprintf("(?i:%s)", strings.Join(regStrArr, "|")))
names = nameRe.FindAllString(userAgent, -1)
name = ""
)
for _, s := range names {
if name == "" {
if len(name) == 0 {
name = strings.TrimSpace(s)
} else if len(name) > 0 {
} else {
if strings.Contains(name, "Macintosh") && s != "" {
name = strings.TrimSpace(s)
} else if strings.Contains(name, s) {
@ -62,30 +67,32 @@ func GetOs(userAgent string) string {
if name != "" {
osName = name
}
return osName
}
// GetBrowser 获取浏览器名称
func GetBrowser(userAgent string) string {
deviceName := "Unknown"
var (
deviceName = consts.Unknown
levelNames = ":VivoBrowser:QQDownload:QQBrowser:QQ:MQQBrowser:MicroMessenger:TencentTraveler:LBBROWSER:TaoBrowser:BrowserNG:UCWEB:TwonkyBeamBrowser:NokiaBrowser:OviBrowser:NF-Browser:OneBrowser:Obigo:DiigoBrowser:baidubrowser:baiduboxapp:xiaomi:Redmi:MI:Lumia:Micromax:MSIEMobile:IEMobile:EdgiOS:Yandex:Mercury:Openwave:TouchPad:UBrowser:Presto:Maxthon:MetaSr:Trident:Opera:IEMobile:Edge:Chrome:Chromium:OPR:CriOS:Firefox:FxiOS:fennec:CrMo:Safari:Nexus One:Nexus S:Nexus:Blazer:teashark:bolt:HTC:Dell:Motorola:Samsung:LG:Sony:SonyST:SonyLT:SonyEricsson:Asus:Palm:Vertu:Pantech:Fly:Wiko:i-mobile:Alcatel:Nintendo:Amoi:INQ:ONEPLUS:Tapatalk:PDA:Novarra-Vision:NetFront:Minimo:FlyFlow:Dolfin:Nokia:Series:AppleWebKit:Mobile:Mozilla:Version:"
namesArr = strings.Split(strings.Trim(levelNames, ":"), ":")
regStrArr []string
)
levelNames := ":VivoBrowser:QQDownload:QQBrowser:QQ:MQQBrowser:MicroMessenger:TencentTraveler:LBBROWSER:TaoBrowser:BrowserNG:UCWEB:TwonkyBeamBrowser:NokiaBrowser:OviBrowser:NF-Browser:OneBrowser:Obigo:DiigoBrowser:baidubrowser:baiduboxapp:xiaomi:Redmi:MI:Lumia:Micromax:MSIEMobile:IEMobile:EdgiOS:Yandex:Mercury:Openwave:TouchPad:UBrowser:Presto:Maxthon:MetaSr:Trident:Opera:IEMobile:Edge:Chrome:Chromium:OPR:CriOS:Firefox:FxiOS:fennec:CrMo:Safari:Nexus One:Nexus S:Nexus:Blazer:teashark:bolt:HTC:Dell:Motorola:Samsung:LG:Sony:SonyST:SonyLT:SonyEricsson:Asus:Palm:Vertu:Pantech:Fly:Wiko:i-mobile:Alcatel:Nintendo:Amoi:INQ:ONEPLUS:Tapatalk:PDA:Novarra-Vision:NetFront:Minimo:FlyFlow:Dolfin:Nokia:Series:AppleWebKit:Mobile:Mozilla:Version:"
var regStrArr []string
namesArr := strings.Split(strings.Trim(levelNames, ":"), ":")
for _, name := range namesArr {
regStrArr = append(regStrArr, fmt.Sprintf("(%s[\\s?\\/0-9.]+)", name))
}
regexpStr := fmt.Sprintf("(?i:%s)", strings.Join(regStrArr, "|"))
nameRe, _ := regexp.Compile(regexpStr)
names := nameRe.FindAllString(userAgent, -1)
level := 0
var (
regexpStr = fmt.Sprintf("(?i:%s)", strings.Join(regStrArr, "|"))
nameRe, _ = regexp.Compile(regexpStr)
names = nameRe.FindAllString(userAgent, -1)
level = 0
)
for _, name := range names {
replaceRe, _ := regexp.Compile(`(?i:[\s?\/0-9.]+)`)
n := replaceRe.ReplaceAllString(name, "")
l := strings.Index(levelNames, fmt.Sprintf(":%s:", n))
l := strings.Index(levelNames, fmt.Sprintf(":%s:", replaceRe.ReplaceAllString(name, "")))
if level == 0 {
deviceName = strings.TrimSpace(name)
}
@ -95,7 +102,6 @@ func GetBrowser(userAgent string) string {
deviceName = strings.TrimSpace(name)
}
}
return deviceName
}
@ -119,6 +125,5 @@ func getWinOsNameWithWinNT(sName string) string {
break
}
}
return osName
}

View File

@ -3,18 +3,16 @@
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package validate
import (
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
)
// 包含判断
// InSliceExistStr 判断字符或切片字符是否存在指定字符
func InSliceExistStr(elems interface{}, search string) bool {
func InSliceExistStr(elems any, search string) bool {
switch elems.(type) {
case []string:
elem := gconv.Strings(elems)
@ -26,35 +24,15 @@ func InSliceExistStr(elems interface{}, search string) bool {
default:
return gconv.String(elems) == search
}
return false
}
// InSliceInt64 元素是否存在于切片中
func InSliceInt64(slice []int64, key int64) bool {
if len(slice) == 0 {
return false
}
for i := 0; i < len(slice); i++ {
if slice[i] == key {
// InSlice 元素是否存在于切片中
func InSlice[K comparable](slice []K, key K) bool {
for _, v := range slice {
if v == key {
return true
}
}
return false
}
func InSliceInt(slice []int, key int) bool {
if len(slice) == 0 {
return false
}
for i := 0; i < len(slice); i++ {
if slice[i] == key {
return true
}
}
return false
}
func InSliceString(slice []string, key string) bool {
return gstr.InArray(slice, key)
}