mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-11-12 20:23:52 +08:00
更新2.1.2版本,优化部门、角色权限,增加上下级关系;增加登录、系统、短信日志;优化省市区编码
This commit is contained in:
@@ -11,34 +11,53 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/mojocn/base64Captcha"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
// GetVerifyImgString 生成验证码
|
||||
func GetVerifyImgString(ctx context.Context) (idKeyC string, base64stringC string) {
|
||||
driver := &base64Captcha.DriverString{
|
||||
Height: 80,
|
||||
Width: 240,
|
||||
//NoiseCount: 50,
|
||||
//ShowLineOptions: 20,
|
||||
Length: 4,
|
||||
Source: "abcdefghjkmnpqrstuvwxyz23456789",
|
||||
Fonts: []string{"chromohv.ttf"},
|
||||
// Generate 生成验证码
|
||||
func Generate(ctx context.Context) (id string, base64 string) {
|
||||
// 字符
|
||||
//driver := &base64Captcha.DriverString{
|
||||
// Height: 42,
|
||||
// Width: 100,
|
||||
// //NoiseCount: 50,
|
||||
// //ShowLineOptions: 20,
|
||||
// Length: 4,
|
||||
// BgColor: &color.RGBA{
|
||||
// R: 255,
|
||||
// G: 250,
|
||||
// B: 250,
|
||||
// A: 250,
|
||||
// },
|
||||
// Source: "0123456789", // abcdefghjkmnpqrstuvwxyz23456789
|
||||
// Fonts: []string{"chromohv.ttf"},
|
||||
//}
|
||||
|
||||
// 计算
|
||||
driver := &base64Captcha.DriverMath{
|
||||
Height: 42,
|
||||
Width: 100,
|
||||
NoiseCount: 0,
|
||||
ShowLineOptions: 0,
|
||||
BgColor: &color.RGBA{
|
||||
R: 255,
|
||||
G: 250,
|
||||
B: 250,
|
||||
A: 250,
|
||||
},
|
||||
Fonts: []string{"chromohv.ttf"},
|
||||
}
|
||||
driver = driver.ConvertFonts()
|
||||
store := base64Captcha.DefaultMemStore
|
||||
c := base64Captcha.NewCaptcha(driver, store)
|
||||
idKeyC, base64stringC, err := c.Generate()
|
||||
|
||||
c := base64Captcha.NewCaptcha(driver.ConvertFonts(), base64Captcha.DefaultMemStore)
|
||||
id, base64, err := c.Generate()
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, err)
|
||||
g.Log().Errorf(ctx, "captcha.Generate err:%+v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// VerifyString 验证输入的验证码是否正确
|
||||
func VerifyString(id, answer string) bool {
|
||||
driver := new(base64Captcha.DriverString)
|
||||
store := base64Captcha.DefaultMemStore
|
||||
c := base64Captcha.NewCaptcha(driver, store)
|
||||
answer = gstr.ToLower(answer)
|
||||
return c.Verify(id, answer, true)
|
||||
// Verify 验证输入的验证码是否正确
|
||||
func Verify(id, answer string) bool {
|
||||
c := base64Captcha.NewCaptcha(new(base64Captcha.DriverString), base64Captcha.DefaultMemStore)
|
||||
return c.Verify(id, gstr.ToLower(answer), true)
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func SetUser(ctx context.Context, user *model.Identity) {
|
||||
Get(ctx).User = user
|
||||
}
|
||||
|
||||
// SetResponse 设置组件响应 用于全局日志使用
|
||||
// SetResponse 设置组件响应 用于访问日志使用
|
||||
func SetResponse(ctx context.Context, response *model.Response) {
|
||||
Get(ctx).Response = response
|
||||
}
|
||||
|
||||
@@ -8,10 +8,53 @@ package views
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
func (l *gCurd) webIndexTplData(ctx context.Context, in *CurdPreviewInput) (data g.Map, err error) {
|
||||
data = make(g.Map)
|
||||
return
|
||||
const (
|
||||
IndexApiImport = " import {%v } from '@/api/%s';"
|
||||
IndexIconsImport = " import {%v } from '@vicons/antd';"
|
||||
)
|
||||
|
||||
func (l *gCurd) webIndexTplData(ctx context.Context, in *CurdPreviewInput) (g.Map, error) {
|
||||
var (
|
||||
data = make(g.Map)
|
||||
apiImport = []string{" List"}
|
||||
iconsImport []string
|
||||
)
|
||||
|
||||
// 添加
|
||||
if in.options.Step.HasAdd {
|
||||
iconsImport = append(iconsImport, " PlusOutlined")
|
||||
}
|
||||
|
||||
// 编辑
|
||||
if in.options.Step.HasEdit {
|
||||
}
|
||||
|
||||
// 导出
|
||||
if in.options.Step.HasExport {
|
||||
iconsImport = append(iconsImport, " ExportOutlined")
|
||||
apiImport = append(apiImport, " Export")
|
||||
}
|
||||
|
||||
// 删除
|
||||
if in.options.Step.HasDel || in.options.Step.HasBatchDel {
|
||||
iconsImport = append(iconsImport, " DeleteOutlined")
|
||||
apiImport = append(apiImport, " Delete")
|
||||
}
|
||||
|
||||
// 导出
|
||||
if in.options.Step.HasStatus {
|
||||
apiImport = append(apiImport, " Status")
|
||||
}
|
||||
|
||||
data["apiImport"] = fmt.Sprintf(IndexApiImport, gstr.Implode(",", apiImport), gstr.LcFirst(in.In.VarName))
|
||||
if len(iconsImport) > 0 {
|
||||
data["iconsImport"] = fmt.Sprintf(IndexIconsImport, gstr.Implode(",", iconsImport))
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
@@ -259,10 +259,10 @@ func (l *gCurd) generateWebModelColumnsEach(buffer *bytes.Buffer, in *CurdPrevie
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (isNullObject(row.%s) || !isArray(row.%s)) {\n return ``;\n }\n return row.%s.map((tagKey) => {\n return h(\n NTag,\n {\n style: {\n marginRight: '6px',\n },\n type: getOptionTag(options.value.%s, tagKey),\n bordered: false,\n },\n {\n default: () => getOptionLabel(options.value.%s, tagKey),\n }\n );\n });\n },\n },\n", field.Dc, field.TsName, field.TsName, field.TsName, field.TsName, in.options.dictMap[field.TsName], in.options.dictMap[field.TsName])
|
||||
|
||||
case FormModeUploadImage:
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n return h(%s, {\n width: 32,\n height: 32,\n src: row.%s,\n style: {\n width: '32px',\n height: '32px',\n 'max-width': '100%%',\n 'max-height': '100%%',\n },\n });\n },\n },\n", field.Dc, field.TsName, "NImage", field.TsName)
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n return h(%s, {\n width: 32,\n height: 32,\n src: row.%s,\n onError: errorImg,\n style: {\n width: '32px',\n height: '32px',\n 'max-width': '100%%',\n 'max-height': '100%%',\n },\n });\n },\n },\n", field.Dc, field.TsName, "NImage", field.TsName)
|
||||
|
||||
case FormModeUploadImages:
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (isNullObject(row.%s)) {\n return ``;\n }\n return row.%s.map((image) => {\n return h(%s, {\n width: 32,\n height: 32,\n src: image,\n style: {\n width: '32px',\n height: '32px',\n 'max-width': '100%%',\n 'max-height': '100%%',\n 'margin-left': '2px',\n },\n });\n });\n },\n },\n", field.Dc, field.TsName, field.TsName, field.TsName, "NImage")
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (isNullObject(row.%s)) {\n return ``;\n }\n return row.%s.map((image) => {\n return h(%s, {\n width: 32,\n height: 32,\n src: image,\n onError: errorImg,\n style: {\n width: '32px',\n height: '32px',\n 'max-width': '100%%',\n 'max-height': '100%%',\n 'margin-left': '2px',\n },\n });\n });\n },\n },\n", field.Dc, field.TsName, field.TsName, field.TsName, "NImage")
|
||||
|
||||
case FormModeUploadFile:
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (row.%s === '') {\n return ``;\n }\n return h(\n %s,\n {\n size: 'small',\n },\n {\n default: () => getFileExt(row.%s),\n }\n );\n },\n },\n", field.Dc, field.TsName, field.TsName, "NAvatar", field.TsName)
|
||||
|
||||
@@ -208,7 +208,7 @@ func IsUnique(ctx context.Context, dao interface{}, where g.Map, message string,
|
||||
// GenSubTree 生成下级关系树
|
||||
func GenSubTree(ctx context.Context, dao interface{}, oldPid int64) (newPid int64, newLevel int, subTree string, err error) {
|
||||
// 顶级树
|
||||
if oldPid == 0 {
|
||||
if oldPid <= 0 {
|
||||
return 0, 1, "", nil
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ func GenSubTree(ctx context.Context, dao interface{}, oldPid int64) (newPid int6
|
||||
return 0, 0, "", err
|
||||
}
|
||||
|
||||
models, err := d.Ctx(ctx).WhereNot(field, oldPid).One()
|
||||
models, err := d.Ctx(ctx).Where(field, oldPid).One()
|
||||
if err != nil {
|
||||
return 0, 0, "", err
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/contexts"
|
||||
"hotgo/internal/model/entity"
|
||||
"hotgo/utility/tree"
|
||||
)
|
||||
|
||||
// HandlerFilterAuth 过滤数据权限
|
||||
@@ -23,7 +24,7 @@ func HandlerFilterAuth(m *gdb.Model) *gdb.Model {
|
||||
var (
|
||||
needAuth bool
|
||||
filterField string
|
||||
roleModel *entity.AdminRole
|
||||
role *entity.AdminRole
|
||||
ctx = m.GetCtx()
|
||||
fields = escapeFieldsToSlice(m.GetFieldsStr())
|
||||
co = contexts.Get(ctx)
|
||||
@@ -48,34 +49,35 @@ func HandlerFilterAuth(m *gdb.Model) *gdb.Model {
|
||||
return m
|
||||
}
|
||||
|
||||
err := g.Model("admin_role").Where("id", co.User.RoleId).Scan(&roleModel)
|
||||
err := g.Model("admin_role").Where("id", co.User.RoleId).Scan(&role)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("HandlerFilterAuth Failed to role information err:%+v", err))
|
||||
panic(fmt.Sprintf("failed to role information err:%+v", err))
|
||||
}
|
||||
|
||||
if roleModel == nil {
|
||||
panic(fmt.Sprintf("HandlerFilterAuth Failed to role information err2:%+v", err))
|
||||
if role == nil {
|
||||
panic("failed to role information roleModel == nil")
|
||||
}
|
||||
|
||||
// TODO 当前不是完整功能,预计在下个版本中完善
|
||||
switch roleModel.DataScope {
|
||||
sq := g.Model("admin_member").Fields("id")
|
||||
|
||||
switch role.DataScope {
|
||||
case consts.RoleDataAll: // 全部权限
|
||||
// ...
|
||||
case consts.RoleDataNowDept: // 当前部门
|
||||
m = m.Where(filterField, co.User.DeptId)
|
||||
m = m.WhereIn(filterField, sq.Where("dept_id", co.User.DeptId))
|
||||
case consts.RoleDataDeptAndSub: // 当前部门及以下部门
|
||||
//m = m.Where(filterField, 1)
|
||||
m = m.WhereIn(filterField, sq.WhereIn("dept_id", GetDeptAndSub(co.User.DeptId)))
|
||||
case consts.RoleDataDeptCustom: // 自定义部门
|
||||
m = m.WhereIn(filterField, roleModel.CustomDept.Var().Ints())
|
||||
m = m.WhereIn(filterField, sq.WhereIn("dept_id", role.CustomDept.Var().Ints()))
|
||||
case consts.RoleDataSelf: // 仅自己
|
||||
m = m.Where(filterField, co.User.Id)
|
||||
case consts.RoleDataSelfAndSub: // 自己和直属下级
|
||||
//m = m.Where(filterField, 1)
|
||||
m = m.WhereIn(filterField, GetSelfAndSub(co.User.Id))
|
||||
case consts.RoleDataSelfAndAllSub: // 自己和全部下级
|
||||
//m = m.Where(filterField, 1)
|
||||
m = m.WhereIn(filterField, GetSelfAndAllSub(co.User.Id))
|
||||
|
||||
default:
|
||||
panic("HandlerFilterAuth dataScope is not registered")
|
||||
panic("dataScope is not registered")
|
||||
}
|
||||
|
||||
return m
|
||||
@@ -90,3 +92,57 @@ func HandlerForceCache(m *gdb.Model) *gdb.Model {
|
||||
func escapeFieldsToSlice(s string) []string {
|
||||
return gstr.Explode(",", gstr.Replace(gstr.Replace(s, "`,`", ","), "`", ""))
|
||||
}
|
||||
|
||||
// GetDeptAndSub 获取指定部门的所有下级,含本部门
|
||||
func GetDeptAndSub(deptId int64) (ids []int64) {
|
||||
array, err := g.Model("admin_dept").
|
||||
WhereLike("tree", "%"+tree.GetIdLabel(deptId)+"%").
|
||||
Fields("id").
|
||||
Array()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range array {
|
||||
ids = append(ids, v.Int64())
|
||||
}
|
||||
|
||||
ids = append(ids, deptId)
|
||||
return
|
||||
}
|
||||
|
||||
// GetSelfAndSub 获取直属下级,包含自己
|
||||
func GetSelfAndSub(memberId int64) (ids []int64) {
|
||||
array, err := g.Model("admin_member").
|
||||
Where("pid", memberId).
|
||||
Fields("id").
|
||||
Array()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range array {
|
||||
ids = append(ids, v.Int64())
|
||||
}
|
||||
|
||||
ids = append(ids, memberId)
|
||||
return
|
||||
}
|
||||
|
||||
// GetSelfAndAllSub 获取全部下级,包含自己
|
||||
func GetSelfAndAllSub(memberId int64) (ids []int64) {
|
||||
array, err := g.Model("admin_member").
|
||||
WhereLike("tree", "%"+tree.GetIdLabel(memberId)+"%").
|
||||
Fields("id").
|
||||
Array()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range array {
|
||||
ids = append(ids, v.Int64())
|
||||
}
|
||||
|
||||
ids = append(ids, memberId)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
)
|
||||
|
||||
// GenerateLoginToken 为指定用户生成token
|
||||
func GenerateLoginToken(ctx context.Context, user *model.Identity, isRefresh bool) (interface{}, error) {
|
||||
func GenerateLoginToken(ctx context.Context, user *model.Identity, isRefresh bool) (string, error) {
|
||||
var (
|
||||
jwtVersion = g.Cfg().MustGet(ctx, "jwt.version", "1.0")
|
||||
jwtSign = g.Cfg().MustGet(ctx, "jwt.sign", "hotGo")
|
||||
@@ -51,7 +51,7 @@ func GenerateLoginToken(ctx context.Context, user *model.Identity, isRefresh boo
|
||||
|
||||
tokenString, err := token.SignedString(jwtSign.Bytes())
|
||||
if err != nil {
|
||||
return nil, gerror.New(err.Error())
|
||||
return "", err
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -65,12 +65,12 @@ func GenerateLoginToken(ctx context.Context, user *model.Identity, isRefresh boo
|
||||
|
||||
err = c.Set(ctx, key, tokenString, expires)
|
||||
if err != nil {
|
||||
return nil, gerror.New(err.Error())
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = c.Set(ctx, consts.RedisJwtUserBind+user.App+":"+gconv.String(user.Id), key, expires)
|
||||
if err != nil {
|
||||
return nil, gerror.New(err.Error())
|
||||
return "", err
|
||||
}
|
||||
return tokenString, err
|
||||
}
|
||||
|
||||
@@ -144,6 +144,11 @@ func GetPublicIP(ctx context.Context) (ip string, err error) {
|
||||
g.Log().Warningf(ctx, "GetPublicIP alternatives are being tried err:%+v", err)
|
||||
return GetPublicIP2()
|
||||
}
|
||||
|
||||
if data == nil {
|
||||
g.Log().Warningf(ctx, "publicIP address Parsing failure, check the network and firewall blocking.")
|
||||
return "0.0.0.0", nil
|
||||
}
|
||||
return data.Ip, nil
|
||||
}
|
||||
|
||||
@@ -190,5 +195,10 @@ func GetClientIp(r *ghttp.Request) string {
|
||||
if ip == "" {
|
||||
ip = r.GetClientIp()
|
||||
}
|
||||
|
||||
// 如果存在多个,默认取第一个
|
||||
if gstr.Contains(ip, ",") {
|
||||
ip = gstr.TrimStr(ip, ",", -1)
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ func InstanceProducer() (mqClient MqProducer, err error) {
|
||||
return NewProducer(config.GroupName)
|
||||
}
|
||||
|
||||
// NewProducer 新建一个生产者实例
|
||||
// NewProducer 初始化生产者实例
|
||||
func NewProducer(groupName string) (mqClient MqProducer, err error) {
|
||||
if item, ok := mqProducerInstanceMap[groupName]; ok {
|
||||
return item, nil
|
||||
@@ -143,7 +143,7 @@ func NewProducer(groupName string) (mqClient MqProducer, err error) {
|
||||
return mqClient, nil
|
||||
}
|
||||
|
||||
// NewConsumer 新建一个消费者实例
|
||||
// NewConsumer 初始化消费者实例
|
||||
func NewConsumer(groupName string) (mqClient MqConsumer, err error) {
|
||||
randTag := string(charset.RandomCreateBytes(6))
|
||||
|
||||
|
||||
@@ -87,30 +87,28 @@ func (r *KafkaMq) ListenReceiveMsgDo(topic string, receiveDo func(mqMsg MqMsg))
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
go func() {
|
||||
|
||||
go func(ctx context.Context) {
|
||||
for {
|
||||
if err := r.consumerIns.Consume(ctx, []string{topic}, &consumer); err != nil {
|
||||
FatalLog(ctx, "kafka Error from consumer", err)
|
||||
g.Log().Fatalf(ctx, "kafka Error from consumer, err%+v", err)
|
||||
}
|
||||
|
||||
if ctx.Err() != nil {
|
||||
Log(ctx, fmt.Sprintf("kafka consoumer stop : %v", ctx.Err()))
|
||||
g.Log().Debugf(ctx, fmt.Sprintf("kafka consoumer stop : %v", ctx.Err()))
|
||||
return
|
||||
}
|
||||
consumer.ready = make(chan bool)
|
||||
}
|
||||
}()
|
||||
}(ctx)
|
||||
|
||||
<-consumer.ready // Await till the consumer has been set up
|
||||
Log(ctx, "kafka consumer up and running!...")
|
||||
g.Log().Debug(ctx, "kafka consumer up and running!...")
|
||||
|
||||
signal.AppDefer(func() {
|
||||
Log(ctx, "kafka consumer close...")
|
||||
g.Log().Debug(ctx, "kafka consumer close...")
|
||||
cancel()
|
||||
if err = r.consumerIns.Close(); err != nil {
|
||||
FatalLog(ctx, "kafka Error closing client", err)
|
||||
g.Log().Fatalf(ctx, "kafka Error closing client, err:%+v", err)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -193,7 +191,7 @@ func RegisterKafkaProducer(connOpt KafkaConfig, mqIns *KafkaMq) {
|
||||
}
|
||||
|
||||
signal.AppDefer(func() {
|
||||
Log(ctx, "kafka producer AsyncClose...")
|
||||
g.Log().Debug(ctx, "kafka producer AsyncClose...")
|
||||
mqIns.producerIns.AsyncClose()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,33 +10,28 @@ import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/utility/charset"
|
||||
)
|
||||
|
||||
const (
|
||||
ConsumerLogErrFormat = "消费 [%s] 失败, mqMsgId:%+v, mqMsgData:%+v, err:%+v, stack:%+v"
|
||||
ProducerLogErrFormat = "生产 [%s] 失败, data:%+v, err:%+v, stack:%+v"
|
||||
)
|
||||
|
||||
// ConsumerLog 消费日志
|
||||
func ConsumerLog(ctx context.Context, topic string, mqMsg MqMsg, err error) {
|
||||
if err != nil {
|
||||
g.Log(consts.QueueLogPath).Error(ctx, "消费 ["+topic+"] 失败", mqMsg, err)
|
||||
g.Log().Printf(ctx, ConsumerLogErrFormat, topic, mqMsg.MsgId, mqMsg.BodyString(), err, charset.ParseErrStack(err))
|
||||
} else {
|
||||
g.Log(consts.QueueLogPath).Debug(ctx, "消费 ["+topic+"] 成功", mqMsg.MsgId)
|
||||
g.Log().Print(ctx, "消费 ["+topic+"] 成功", mqMsg.MsgId)
|
||||
}
|
||||
}
|
||||
|
||||
// ProducerLog 生产日志
|
||||
func ProducerLog(ctx context.Context, topic string, data interface{}, err error) {
|
||||
if err != nil {
|
||||
g.Log(consts.QueueLogPath).Error(ctx, "生产 ["+topic+"] 失败", gconv.String(data))
|
||||
g.Log().Printf(ctx, ProducerLogErrFormat, topic, gconv.String(data), err, charset.ParseErrStack(err))
|
||||
} else {
|
||||
g.Log(consts.QueueLogPath).Debug(ctx, "生产 ["+topic+"] 成功", gconv.String(data))
|
||||
g.Log().Print(ctx, "生产 ["+topic+"] 成功", gconv.String(data))
|
||||
}
|
||||
}
|
||||
|
||||
// FatalLog 致命日志
|
||||
func FatalLog(ctx context.Context, text string, err error) {
|
||||
g.Log(consts.QueueLogPath).Fatal(ctx, text+":", err)
|
||||
}
|
||||
|
||||
// Log 通用日志
|
||||
func Log(ctx context.Context, text string) {
|
||||
g.Log(consts.QueueLogPath).Debug(ctx, text)
|
||||
}
|
||||
|
||||
18
server/internal/library/queue/push.go
Normal file
18
server/internal/library/queue/push.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package queue
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// Push 推送队列
|
||||
func Push(topic string, data interface{}) (err error) {
|
||||
q, err := InstanceProducer()
|
||||
if err != nil {
|
||||
g.Log().Fatalf(ctx, "queue.InstanceProducer err:%+v", err)
|
||||
return err
|
||||
}
|
||||
mqMsg, err := q.SendMsg(topic, gconv.String(data))
|
||||
ProducerLog(ctx, topic, mqMsg.MsgId, err)
|
||||
return err
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/utility/encrypt"
|
||||
"math/rand"
|
||||
"time"
|
||||
@@ -113,7 +112,7 @@ func (r *RedisMq) ListenReceiveMsgDo(topic string, receiveDo func(mqMsg MqMsg))
|
||||
|
||||
// 生成队列名称
|
||||
func (r *RedisMq) genQueueName(groupName string, topic string) string {
|
||||
return fmt.Sprintf(consts.QueueName+"%s_%s", groupName, topic)
|
||||
return fmt.Sprintf("queue:%s_%s", groupName, topic)
|
||||
}
|
||||
|
||||
func (r *RedisMq) loopReadQueue(queueName string) (mqMsgList []MqMsg) {
|
||||
|
||||
@@ -26,8 +26,8 @@ type RocketMq struct {
|
||||
|
||||
// rewriteLog 重写日志
|
||||
func rewriteLog() {
|
||||
level := g.Cfg().MustGet(ctx, "queue.rocketmq.logLevel", "debug")
|
||||
rlog.SetLogger(&RocketMqLogger{Flag: "[rocket_mq]", LevelLog: level.String()})
|
||||
level := g.Cfg().MustGet(ctx, "queue.rocketmq.logLevel", "debug").String()
|
||||
rlog.SetLogger(&RocketMqLogger{Flag: "[rocket_mq]", LevelLog: level})
|
||||
}
|
||||
|
||||
// RegisterRocketProducerMust 注册并启动生产者接口实现
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
package queue
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type RocketMqLogger struct {
|
||||
@@ -24,16 +24,16 @@ func (l *RocketMqLogger) Debug(msg string, fields map[string]interface{}) {
|
||||
}
|
||||
|
||||
if l.LevelLog == "debug" || l.LevelLog == "all" {
|
||||
Log(ctx, fmt.Sprint(l.Flag, " [debug] ", msg))
|
||||
g.Log().Debug(ctx, msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *RocketMqLogger) Level(level string) {
|
||||
Log(ctx, fmt.Sprint(l.Flag, " [level] ", level))
|
||||
g.Log().Info(ctx, level)
|
||||
}
|
||||
|
||||
func (l *RocketMqLogger) OutputPath(path string) (err error) {
|
||||
Log(ctx, fmt.Sprint(l.Flag, " [path] ", path))
|
||||
g.Log().Info(ctx, path)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ func (l *RocketMqLogger) Info(msg string, fields map[string]interface{}) {
|
||||
}
|
||||
|
||||
if l.LevelLog == "info" || l.LevelLog == "all" {
|
||||
Log(ctx, fmt.Sprint(l.Flag, " [info] ", msg))
|
||||
g.Log().Info(ctx, msg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func (l *RocketMqLogger) Warning(msg string, fields map[string]interface{}) {
|
||||
}
|
||||
|
||||
if l.LevelLog == "warn" || l.LevelLog == "all" {
|
||||
Log(ctx, fmt.Sprint(l.Flag, " [warn] ", msg))
|
||||
g.Log().Warning(ctx, msg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func (l *RocketMqLogger) Error(msg string, fields map[string]interface{}) {
|
||||
return
|
||||
}
|
||||
if l.LevelLog == "error" || l.LevelLog == "all" {
|
||||
Log(ctx, fmt.Sprint(l.Flag, " [error] ", msg))
|
||||
g.Log().Error(ctx, msg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,6 @@ func (l *RocketMqLogger) Fatal(msg string, fields map[string]interface{}) {
|
||||
}
|
||||
|
||||
if l.LevelLog == "fatal" || l.LevelLog == "all" {
|
||||
Log(ctx, fmt.Sprint(l.Flag, " [fatal] ", msg))
|
||||
g.Log().Fatal(ctx, msg)
|
||||
}
|
||||
}
|
||||
|
||||
112
server/internal/library/sms/aliyun/handle.go
Normal file
112
server/internal/library/sms/aliyun/handle.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package aliyun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v3/client"
|
||||
util "github.com/alibabacloud-go/tea-utils/v2/service"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
|
||||
// SendCode 发送验证码
|
||||
func SendCode(ctx context.Context, in sysin.SendCodeInp, config *model.SmsConfig) (err error) {
|
||||
if config == nil {
|
||||
config, err = service.SysConfig().GetSms(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
client, err := CreateClient(tea.String(config.SmsAliyunAccessKeyID), tea.String(config.SmsAliyunAccessKeySecret))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
|
||||
PhoneNumbers: tea.String(in.Mobile),
|
||||
SignName: tea.String(config.SmsAliyunSign),
|
||||
TemplateCode: tea.String(in.Template),
|
||||
TemplateParam: tea.String(fmt.Sprintf("{\"code\":\"%v\"}", in.Code)),
|
||||
}
|
||||
|
||||
tryErr := func() (_e error) {
|
||||
defer func() {
|
||||
if r := tea.Recover(recover()); r != nil {
|
||||
_e = r
|
||||
}
|
||||
}()
|
||||
|
||||
// 复制代码运行请自行打印 API 的返回值
|
||||
_, err = client.SendSmsWithOptions(sendSmsRequest, &util.RuntimeOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
return tryErr
|
||||
}
|
||||
|
||||
// CreateClient 使用AK&SK初始化账号Client
|
||||
func CreateClient(accessKeyId *string, accessKeySecret *string) (_result *dysmsapi20170525.Client, _err error) {
|
||||
config := &openapi.Config{
|
||||
// 必填,您的 AccessKey ID
|
||||
AccessKeyId: accessKeyId,
|
||||
// 必填,您的 AccessKey Secret
|
||||
AccessKeySecret: accessKeySecret,
|
||||
}
|
||||
// 访问的域名
|
||||
config.Endpoint = tea.String("dysmsapi.aliyuncs.com")
|
||||
_result = &dysmsapi20170525.Client{}
|
||||
_result, _err = dysmsapi20170525.NewClient(config)
|
||||
return _result, _err
|
||||
}
|
||||
|
||||
func Send(accessKeyId string, accessKeySecret string) (_err error) {
|
||||
// 工程代码泄露可能会导致AccessKey泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378661.html
|
||||
client, _err := CreateClient(tea.String(accessKeyId), tea.String(accessKeySecret))
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
||||
sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
|
||||
PhoneNumbers: tea.String("15303830571"),
|
||||
SignName: tea.String("布帆云"),
|
||||
TemplateCode: tea.String("SMS_198921686"),
|
||||
TemplateParam: tea.String("{\"code\":\"1234\"}"),
|
||||
}
|
||||
runtime := &util.RuntimeOptions{}
|
||||
tryErr := func() (_e error) {
|
||||
defer func() {
|
||||
if r := tea.Recover(recover()); r != nil {
|
||||
_e = r
|
||||
}
|
||||
}()
|
||||
// 复制代码运行请自行打印 API 的返回值
|
||||
_, _err = client.SendSmsWithOptions(sendSmsRequest, runtime)
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
if tryErr != nil {
|
||||
var err = &tea.SDKError{}
|
||||
if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||
err = _t
|
||||
} else {
|
||||
err.Message = tea.String(tryErr.Error())
|
||||
}
|
||||
// 如有需要,请打印 error
|
||||
_, _err = util.AssertAsString(err.Message)
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
}
|
||||
return _err
|
||||
}
|
||||
1
server/internal/library/sms/aliyun/init.go
Normal file
1
server/internal/library/sms/aliyun/init.go
Normal file
@@ -0,0 +1 @@
|
||||
package aliyun
|
||||
1
server/internal/library/sms/aliyun/model.go
Normal file
1
server/internal/library/sms/aliyun/model.go
Normal file
@@ -0,0 +1 @@
|
||||
package aliyun
|
||||
2
server/internal/library/sms/sms.go
Normal file
2
server/internal/library/sms/sms.go
Normal file
@@ -0,0 +1,2 @@
|
||||
package sms
|
||||
|
||||
Reference in New Issue
Block a user