mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 00:10:25 +08:00 
			
		
		
		
	feat: 代码优化、机器计划任务完善
This commit is contained in:
		@@ -251,7 +251,6 @@ onMounted(async () => {
 | 
				
			|||||||
const handleCommand = (commond: any) => {
 | 
					const handleCommand = (commond: any) => {
 | 
				
			||||||
    const data = commond.data;
 | 
					    const data = commond.data;
 | 
				
			||||||
    const type = commond.type;
 | 
					    const type = commond.type;
 | 
				
			||||||
    console.log(type);
 | 
					 | 
				
			||||||
    switch (type) {
 | 
					    switch (type) {
 | 
				
			||||||
        case 'detail': {
 | 
					        case 'detail': {
 | 
				
			||||||
            showInfo(data);
 | 
					            showInfo(data);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,14 +3,14 @@ package api
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/pkg/biz"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/pkg/req"
 | 
						"mayfly-go/pkg/req"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/cryptox"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Common struct {
 | 
					type Common struct {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (i *Common) RasPublicKey(rc *req.Ctx) {
 | 
					func (i *Common) RasPublicKey(rc *req.Ctx) {
 | 
				
			||||||
	publicKeyStr, err := utils.GetRsaPublicKey()
 | 
						publicKeyStr, err := cryptox.GetRsaPublicKey()
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "rsa生成公私钥失败")
 | 
						biz.ErrIsNilAppendErr(err, "rsa生成公私钥失败")
 | 
				
			||||||
	rc.ResData = publicKeyStr
 | 
						rc.ResData = publicKeyStr
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,9 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/gormx"
 | 
						"mayfly-go/pkg/gormx"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/req"
 | 
						"mayfly-go/pkg/req"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/cryptox"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/structx"
 | 
				
			||||||
	"mayfly-go/pkg/ws"
 | 
						"mayfly-go/pkg/ws"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@@ -57,7 +59,7 @@ func (d *Db) Save(rc *req.Ctx) {
 | 
				
			|||||||
	db := ginx.BindJsonAndCopyTo[*entity.Db](rc.GinCtx, form, new(entity.Db))
 | 
						db := ginx.BindJsonAndCopyTo[*entity.Db](rc.GinCtx, form, new(entity.Db))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 密码解密,并使用解密后的赋值
 | 
						// 密码解密,并使用解密后的赋值
 | 
				
			||||||
	originPwd, err := utils.DefaultRsaDecrypt(form.Password, true)
 | 
						originPwd, err := cryptox.DefaultRsaDecrypt(form.Password, true)
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "解密密码错误: %s")
 | 
						biz.ErrIsNilAppendErr(err, "解密密码错误: %s")
 | 
				
			||||||
	db.Password = originPwd
 | 
						db.Password = originPwd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -83,10 +85,10 @@ func (d *Db) GetDatabaseNames(rc *req.Ctx) {
 | 
				
			|||||||
	ginx.BindJsonAndValid(rc.GinCtx, form)
 | 
						ginx.BindJsonAndValid(rc.GinCtx, form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	db := new(entity.Db)
 | 
						db := new(entity.Db)
 | 
				
			||||||
	utils.Copy(db, form)
 | 
						structx.Copy(db, form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 密码解密,并使用解密后的赋值
 | 
						// 密码解密,并使用解密后的赋值
 | 
				
			||||||
	originPwd, err := utils.DefaultRsaDecrypt(form.Password, true)
 | 
						originPwd, err := cryptox.DefaultRsaDecrypt(form.Password, true)
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "解密密码错误: %s")
 | 
						biz.ErrIsNilAppendErr(err, "解密密码错误: %s")
 | 
				
			||||||
	db.Password = originPwd
 | 
						db.Password = originPwd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -143,7 +145,7 @@ func (d *Db) ExecSql(rc *req.Ctx) {
 | 
				
			|||||||
	biz.NotEmpty(form.Sql, "sql不能为空")
 | 
						biz.NotEmpty(form.Sql, "sql不能为空")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 去除前后空格及换行符
 | 
						// 去除前后空格及换行符
 | 
				
			||||||
	sql := utils.StrTrimSpaceAndBr(form.Sql)
 | 
						sql := stringx.TrimSpaceAndBr(form.Sql)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	execReq := &application.DbSqlExecReq{
 | 
						execReq := &application.DbSqlExecReq{
 | 
				
			||||||
		DbId:         id,
 | 
							DbId:         id,
 | 
				
			||||||
@@ -158,7 +160,7 @@ func (d *Db) ExecSql(rc *req.Ctx) {
 | 
				
			|||||||
	isMulti := len(sqls) > 1
 | 
						isMulti := len(sqls) > 1
 | 
				
			||||||
	var execResAll *application.DbSqlExecRes
 | 
						var execResAll *application.DbSqlExecRes
 | 
				
			||||||
	for _, s := range sqls {
 | 
						for _, s := range sqls {
 | 
				
			||||||
		s = utils.StrTrimSpaceAndBr(s)
 | 
							s = stringx.TrimSpaceAndBr(s)
 | 
				
			||||||
		// 多条执行,如果有查询语句,则跳过
 | 
							// 多条执行,如果有查询语句,则跳过
 | 
				
			||||||
		if isMulti && strings.HasPrefix(strings.ToLower(s), "select") {
 | 
							if isMulti && strings.HasPrefix(strings.ToLower(s), "select") {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
@@ -308,7 +310,7 @@ func (d *Db) DumpSql(rc *req.Ctx) {
 | 
				
			|||||||
					if ok {
 | 
										if ok {
 | 
				
			||||||
						values = append(values, fmt.Sprintf("%#v", strValue))
 | 
											values = append(values, fmt.Sprintf("%#v", strValue))
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						values = append(values, utils.ToString(value))
 | 
											values = append(values, stringx.AnyToStr(value))
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				writer.WriteString(fmt.Sprintf(insertSql, table, strings.Join(values, ", ")))
 | 
									writer.WriteString(fmt.Sprintf(insertSql, table, strings.Join(values, ", ")))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,8 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/cache"
 | 
						"mayfly-go/pkg/cache"
 | 
				
			||||||
	"mayfly-go/pkg/global"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/collx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/structx"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@@ -120,7 +121,7 @@ func (d *dbAppImpl) Save(dbEntity *entity.Db) {
 | 
				
			|||||||
		newDbs = append(newDbs, v)
 | 
							newDbs = append(newDbs, v)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// 比较新旧数据库列表,需要将移除的数据库相关联的信息删除
 | 
						// 比较新旧数据库列表,需要将移除的数据库相关联的信息删除
 | 
				
			||||||
	_, delDb, _ := utils.ArrayCompare(newDbs, oldDbs, func(i1, i2 any) bool {
 | 
						_, delDb, _ := collx.ArrayCompare(newDbs, oldDbs, func(i1, i2 any) bool {
 | 
				
			||||||
		return i1.(string) == i2.(string)
 | 
							return i1.(string) == i2.(string)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	for _, v := range delDb {
 | 
						for _, v := range delDb {
 | 
				
			||||||
@@ -193,7 +194,7 @@ func (da *dbAppImpl) GetDbInstance(id uint64, db string) *DbInstance {
 | 
				
			|||||||
	d.PwdDecrypt()
 | 
						d.PwdDecrypt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dbInfo := new(DbInfo)
 | 
						dbInfo := new(DbInfo)
 | 
				
			||||||
	utils.Copy(dbInfo, d)
 | 
						structx.Copy(dbInfo, d)
 | 
				
			||||||
	dbInfo.Database = db
 | 
						dbInfo.Database = db
 | 
				
			||||||
	dbi := &DbInstance{Id: cacheKey, Info: dbInfo}
 | 
						dbi := &DbInstance{Id: cacheKey, Info: dbInfo}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ package application
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"embed"
 | 
						"embed"
 | 
				
			||||||
	"mayfly-go/pkg/biz"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -88,7 +88,7 @@ func GetLocalSql(file, key string) string {
 | 
				
			|||||||
	sqls := strings.Split(allSql, "---------------------------------------")
 | 
						sqls := strings.Split(allSql, "---------------------------------------")
 | 
				
			||||||
	var resSql string
 | 
						var resSql string
 | 
				
			||||||
	for _, sql := range sqls {
 | 
						for _, sql := range sqls {
 | 
				
			||||||
		sql = utils.StrTrimSpaceAndBr(sql)
 | 
							sql = stringx.TrimSpaceAndBr(sql)
 | 
				
			||||||
		// 获取sql第一行的sql备注信息如:--MYSQL_TABLE_MA 表信息元数据
 | 
							// 获取sql第一行的sql备注信息如:--MYSQL_TABLE_MA 表信息元数据
 | 
				
			||||||
		info := strings.SplitN(sql, "\n", 2)
 | 
							info := strings.SplitN(sql, "\n", 2)
 | 
				
			||||||
		// 原始sql,即去除第一行的key与备注信息
 | 
							// 原始sql,即去除第一行的key与备注信息
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/internal/db/domain/entity"
 | 
						"mayfly-go/internal/db/domain/entity"
 | 
				
			||||||
	machineapp "mayfly-go/internal/machine/application"
 | 
						machineapp "mayfly-go/internal/machine/application"
 | 
				
			||||||
	"mayfly-go/pkg/biz"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/anyx"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/go-sql-driver/mysql"
 | 
						"github.com/go-sql-driver/mysql"
 | 
				
			||||||
@@ -51,7 +51,7 @@ func (mm *MysqlMetadata) GetTables() []Table {
 | 
				
			|||||||
	for _, re := range res {
 | 
						for _, re := range res {
 | 
				
			||||||
		tables = append(tables, Table{
 | 
							tables = append(tables, Table{
 | 
				
			||||||
			TableName:    re["tableName"].(string),
 | 
								TableName:    re["tableName"].(string),
 | 
				
			||||||
			TableComment: utils.Any2String(re["tableComment"]),
 | 
								TableComment: anyx.ConvString(re["tableComment"]),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return tables
 | 
						return tables
 | 
				
			||||||
@@ -74,11 +74,11 @@ func (mm *MysqlMetadata) GetColumns(tableNames ...string) []Column {
 | 
				
			|||||||
		columns = append(columns, Column{
 | 
							columns = append(columns, Column{
 | 
				
			||||||
			TableName:     re["tableName"].(string),
 | 
								TableName:     re["tableName"].(string),
 | 
				
			||||||
			ColumnName:    re["columnName"].(string),
 | 
								ColumnName:    re["columnName"].(string),
 | 
				
			||||||
			ColumnType:    utils.Any2String(re["columnType"]),
 | 
								ColumnType:    anyx.ConvString(re["columnType"]),
 | 
				
			||||||
			ColumnComment: utils.Any2String(re["columnComment"]),
 | 
								ColumnComment: anyx.ConvString(re["columnComment"]),
 | 
				
			||||||
			Nullable:      utils.Any2String(re["nullable"]),
 | 
								Nullable:      anyx.ConvString(re["nullable"]),
 | 
				
			||||||
			ColumnKey:     utils.Any2String(re["columnKey"]),
 | 
								ColumnKey:     anyx.ConvString(re["columnKey"]),
 | 
				
			||||||
			ColumnDefault: utils.Any2String(re["columnDefault"]),
 | 
								ColumnDefault: anyx.ConvString(re["columnDefault"]),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return columns
 | 
						return columns
 | 
				
			||||||
@@ -106,11 +106,11 @@ func (mm *MysqlMetadata) GetTableInfos() []Table {
 | 
				
			|||||||
	for _, re := range res {
 | 
						for _, re := range res {
 | 
				
			||||||
		tables = append(tables, Table{
 | 
							tables = append(tables, Table{
 | 
				
			||||||
			TableName:    re["tableName"].(string),
 | 
								TableName:    re["tableName"].(string),
 | 
				
			||||||
			TableComment: utils.Any2String(re["tableComment"]),
 | 
								TableComment: anyx.ConvString(re["tableComment"]),
 | 
				
			||||||
			CreateTime:   utils.Any2String(re["createTime"]),
 | 
								CreateTime:   anyx.ConvString(re["createTime"]),
 | 
				
			||||||
			TableRows:    utils.Any2Int(re["tableRows"]),
 | 
								TableRows:    anyx.ConvInt(re["tableRows"]),
 | 
				
			||||||
			DataLength:   utils.Any2Int64(re["dataLength"]),
 | 
								DataLength:   anyx.ConvInt64(re["dataLength"]),
 | 
				
			||||||
			IndexLength:  utils.Any2Int64(re["indexLength"]),
 | 
								IndexLength:  anyx.ConvInt64(re["indexLength"]),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return tables
 | 
						return tables
 | 
				
			||||||
@@ -124,11 +124,11 @@ func (mm *MysqlMetadata) GetTableIndex(tableName string) []Index {
 | 
				
			|||||||
	for _, re := range res {
 | 
						for _, re := range res {
 | 
				
			||||||
		indexs = append(indexs, Index{
 | 
							indexs = append(indexs, Index{
 | 
				
			||||||
			IndexName:    re["indexName"].(string),
 | 
								IndexName:    re["indexName"].(string),
 | 
				
			||||||
			ColumnName:   utils.Any2String(re["columnName"]),
 | 
								ColumnName:   anyx.ConvString(re["columnName"]),
 | 
				
			||||||
			IndexType:    utils.Any2String(re["indexType"]),
 | 
								IndexType:    anyx.ConvString(re["indexType"]),
 | 
				
			||||||
			IndexComment: utils.Any2String(re["indexComment"]),
 | 
								IndexComment: anyx.ConvString(re["indexComment"]),
 | 
				
			||||||
			NonUnique:    utils.Any2Int(re["nonUnique"]),
 | 
								NonUnique:    anyx.ConvInt(re["nonUnique"]),
 | 
				
			||||||
			SeqInIndex:   utils.Any2Int(re["seqInIndex"]),
 | 
								SeqInIndex:   anyx.ConvInt(re["seqInIndex"]),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// 把查询结果以索引名分组,索引字段以逗号连接
 | 
						// 把查询结果以索引名分组,索引字段以逗号连接
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,8 @@ import (
 | 
				
			|||||||
	"mayfly-go/internal/db/domain/entity"
 | 
						"mayfly-go/internal/db/domain/entity"
 | 
				
			||||||
	machineapp "mayfly-go/internal/machine/application"
 | 
						machineapp "mayfly-go/internal/machine/application"
 | 
				
			||||||
	"mayfly-go/pkg/biz"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/anyx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/collx"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -21,7 +22,7 @@ func getPgsqlDB(d *entity.Db, db string) (*sql.DB, error) {
 | 
				
			|||||||
	if d.SshTunnelMachineId > 0 {
 | 
						if d.SshTunnelMachineId > 0 {
 | 
				
			||||||
		// 如果使用了隧道,则使用`postgres:ssh:隧道机器id`注册名
 | 
							// 如果使用了隧道,则使用`postgres:ssh:隧道机器id`注册名
 | 
				
			||||||
		driverName = fmt.Sprintf("postgres:ssh:%d", d.SshTunnelMachineId)
 | 
							driverName = fmt.Sprintf("postgres:ssh:%d", d.SshTunnelMachineId)
 | 
				
			||||||
		if !utils.ArrContains(sql.Drivers(), driverName) {
 | 
							if !collx.ArrayContains(sql.Drivers(), driverName) {
 | 
				
			||||||
			sql.Register(driverName, &PqSqlDialer{sshTunnelMachineId: d.SshTunnelMachineId})
 | 
								sql.Register(driverName, &PqSqlDialer{sshTunnelMachineId: d.SshTunnelMachineId})
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		sql.Drivers()
 | 
							sql.Drivers()
 | 
				
			||||||
@@ -78,7 +79,7 @@ func (pm *PgsqlMetadata) GetTables() []Table {
 | 
				
			|||||||
	for _, re := range res {
 | 
						for _, re := range res {
 | 
				
			||||||
		tables = append(tables, Table{
 | 
							tables = append(tables, Table{
 | 
				
			||||||
			TableName:    re["tableName"].(string),
 | 
								TableName:    re["tableName"].(string),
 | 
				
			||||||
			TableComment: utils.Any2String(re["tableComment"]),
 | 
								TableComment: anyx.ConvString(re["tableComment"]),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return tables
 | 
						return tables
 | 
				
			||||||
@@ -101,11 +102,11 @@ func (pm *PgsqlMetadata) GetColumns(tableNames ...string) []Column {
 | 
				
			|||||||
		columns = append(columns, Column{
 | 
							columns = append(columns, Column{
 | 
				
			||||||
			TableName:     re["tableName"].(string),
 | 
								TableName:     re["tableName"].(string),
 | 
				
			||||||
			ColumnName:    re["columnName"].(string),
 | 
								ColumnName:    re["columnName"].(string),
 | 
				
			||||||
			ColumnType:    utils.Any2String(re["columnType"]),
 | 
								ColumnType:    anyx.ConvString(re["columnType"]),
 | 
				
			||||||
			ColumnComment: utils.Any2String(re["columnComment"]),
 | 
								ColumnComment: anyx.ConvString(re["columnComment"]),
 | 
				
			||||||
			Nullable:      utils.Any2String(re["nullable"]),
 | 
								Nullable:      anyx.ConvString(re["nullable"]),
 | 
				
			||||||
			ColumnKey:     utils.Any2String(re["columnKey"]),
 | 
								ColumnKey:     anyx.ConvString(re["columnKey"]),
 | 
				
			||||||
			ColumnDefault: utils.Any2String(re["columnDefault"]),
 | 
								ColumnDefault: anyx.ConvString(re["columnDefault"]),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return columns
 | 
						return columns
 | 
				
			||||||
@@ -132,11 +133,11 @@ func (pm *PgsqlMetadata) GetTableInfos() []Table {
 | 
				
			|||||||
	for _, re := range res {
 | 
						for _, re := range res {
 | 
				
			||||||
		tables = append(tables, Table{
 | 
							tables = append(tables, Table{
 | 
				
			||||||
			TableName:    re["tableName"].(string),
 | 
								TableName:    re["tableName"].(string),
 | 
				
			||||||
			TableComment: utils.Any2String(re["tableComment"]),
 | 
								TableComment: anyx.ConvString(re["tableComment"]),
 | 
				
			||||||
			CreateTime:   utils.Any2String(re["createTime"]),
 | 
								CreateTime:   anyx.ConvString(re["createTime"]),
 | 
				
			||||||
			TableRows:    utils.Any2Int(re["tableRows"]),
 | 
								TableRows:    anyx.ConvInt(re["tableRows"]),
 | 
				
			||||||
			DataLength:   utils.Any2Int64(re["dataLength"]),
 | 
								DataLength:   anyx.ConvInt64(re["dataLength"]),
 | 
				
			||||||
			IndexLength:  utils.Any2Int64(re["indexLength"]),
 | 
								IndexLength:  anyx.ConvInt64(re["indexLength"]),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return tables
 | 
						return tables
 | 
				
			||||||
@@ -150,11 +151,11 @@ func (pm *PgsqlMetadata) GetTableIndex(tableName string) []Index {
 | 
				
			|||||||
	for _, re := range res {
 | 
						for _, re := range res {
 | 
				
			||||||
		indexs = append(indexs, Index{
 | 
							indexs = append(indexs, Index{
 | 
				
			||||||
			IndexName:    re["indexName"].(string),
 | 
								IndexName:    re["indexName"].(string),
 | 
				
			||||||
			ColumnName:   utils.Any2String(re["columnName"]),
 | 
								ColumnName:   anyx.ConvString(re["columnName"]),
 | 
				
			||||||
			IndexType:    utils.Any2String(re["indexType"]),
 | 
								IndexType:    anyx.ConvString(re["indexType"]),
 | 
				
			||||||
			IndexComment: utils.Any2String(re["indexComment"]),
 | 
								IndexComment: anyx.ConvString(re["indexComment"]),
 | 
				
			||||||
			NonUnique:    utils.Any2Int(re["nonUnique"]),
 | 
								NonUnique:    anyx.ConvInt(re["nonUnique"]),
 | 
				
			||||||
			SeqInIndex:   utils.Any2Int(re["seqInIndex"]),
 | 
								SeqInIndex:   anyx.ConvInt(re["seqInIndex"]),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return indexs
 | 
						return indexs
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,8 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/ginx"
 | 
						"mayfly-go/pkg/ginx"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/req"
 | 
						"mayfly-go/pkg/req"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/structx"
 | 
				
			||||||
	"mayfly-go/pkg/ws"
 | 
						"mayfly-go/pkg/ws"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
@@ -82,7 +83,7 @@ func (m *Machine) TestConn(rc *req.Ctx) {
 | 
				
			|||||||
	ginx.BindJsonAndValid(g, machineForm)
 | 
						ginx.BindJsonAndValid(g, machineForm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	me := new(entity.Machine)
 | 
						me := new(entity.Machine)
 | 
				
			||||||
	utils.Copy(me, machineForm)
 | 
						structx.Copy(me, machineForm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m.MachineApp.TestConn(me)
 | 
						m.MachineApp.TestConn(me)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -192,7 +193,7 @@ func (m *Machine) WsSSH(g *gin.Context) {
 | 
				
			|||||||
		recorder = machine.NewRecorder(f)
 | 
							recorder = machine.NewRecorder(f)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mts, err := machine.NewTerminalSession(utils.RandString(16), wsConn, cli, rows, cols, recorder)
 | 
						mts, err := machine.NewTerminalSession(stringx.Rand(16), wsConn, cli, rows, cols, recorder)
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "\033[1;31m连接失败: %s\033[0m")
 | 
						biz.ErrIsNilAppendErr(err, "\033[1;31m连接失败: %s\033[0m")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 记录系统操作日志
 | 
						// 记录系统操作日志
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,8 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/biz"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/pkg/ginx"
 | 
						"mayfly-go/pkg/ginx"
 | 
				
			||||||
	"mayfly-go/pkg/req"
 | 
						"mayfly-go/pkg/req"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/jsonx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -63,7 +64,7 @@ func (m *MachineScript) RunMachineScript(rc *req.Ctx) {
 | 
				
			|||||||
	script := ms.Script
 | 
						script := ms.Script
 | 
				
			||||||
	// 如果有脚本参数,则用脚本参数替换脚本中的模板占位符参数
 | 
						// 如果有脚本参数,则用脚本参数替换脚本中的模板占位符参数
 | 
				
			||||||
	if params := g.Query("params"); params != "" {
 | 
						if params := g.Query("params"); params != "" {
 | 
				
			||||||
		script = utils.TemplateParse(ms.Script, utils.Json2Map(params))
 | 
							script = stringx.TemplateParse(ms.Script, jsonx.ToMap(params))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cli := m.MachineApp.GetCli(machineId)
 | 
						cli := m.MachineApp.GetCli(machineId)
 | 
				
			||||||
	biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().TagPath), "%s")
 | 
						biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().TagPath), "%s")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,8 +5,10 @@ import (
 | 
				
			|||||||
	"mayfly-go/internal/machine/domain/repository"
 | 
						"mayfly-go/internal/machine/domain/repository"
 | 
				
			||||||
	"mayfly-go/pkg/global"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/rediscli"
 | 
				
			||||||
	"mayfly-go/pkg/scheduler"
 | 
						"mayfly-go/pkg/scheduler"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/collx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -107,7 +109,7 @@ func (m *machineCropJobAppImpl) GetRelateCronJobIds(machineId uint64) []uint64 {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (m *machineCropJobAppImpl) CronJobRelateMachines(cronJobId uint64, machineIds []uint64, la *model.LoginAccount) {
 | 
					func (m *machineCropJobAppImpl) CronJobRelateMachines(cronJobId uint64, machineIds []uint64, la *model.LoginAccount) {
 | 
				
			||||||
	oldMachineIds := m.machineCropJobRelateRepo.GetMachineIds(cronJobId)
 | 
						oldMachineIds := m.machineCropJobRelateRepo.GetMachineIds(cronJobId)
 | 
				
			||||||
	addIds, delIds, _ := utils.ArrayCompare[uint64](machineIds, oldMachineIds, func(u1, u2 uint64) bool { return u1 == u2 })
 | 
						addIds, delIds, _ := collx.ArrayCompare[uint64](machineIds, oldMachineIds, func(u1, u2 uint64) bool { return u1 == u2 })
 | 
				
			||||||
	addVals := make([]*entity.MachineCronJobRelate, 0)
 | 
						addVals := make([]*entity.MachineCronJobRelate, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	now := time.Now()
 | 
						now := time.Now()
 | 
				
			||||||
@@ -129,7 +131,7 @@ func (m *machineCropJobAppImpl) CronJobRelateMachines(cronJobId uint64, machineI
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (m *machineCropJobAppImpl) MachineRelateCronJobs(machineId uint64, cronJobs []uint64, la *model.LoginAccount) {
 | 
					func (m *machineCropJobAppImpl) MachineRelateCronJobs(machineId uint64, cronJobs []uint64, la *model.LoginAccount) {
 | 
				
			||||||
	oldCronIds := m.machineCropJobRelateRepo.GetCronJobIds(machineId)
 | 
						oldCronIds := m.machineCropJobRelateRepo.GetCronJobIds(machineId)
 | 
				
			||||||
	addIds, delIds, _ := utils.ArrayCompare[uint64](cronJobs, oldCronIds, func(u1, u2 uint64) bool { return u1 == u2 })
 | 
						addIds, delIds, _ := collx.ArrayCompare[uint64](cronJobs, oldCronIds, func(u1, u2 uint64) bool { return u1 == u2 })
 | 
				
			||||||
	addVals := make([]*entity.MachineCronJobRelate, 0)
 | 
						addVals := make([]*entity.MachineCronJobRelate, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	now := time.Now()
 | 
						now := time.Now()
 | 
				
			||||||
@@ -186,7 +188,7 @@ func (m *machineCropJobAppImpl) addCronJob(mcj *entity.MachineCronJob) {
 | 
				
			|||||||
	var key string
 | 
						var key string
 | 
				
			||||||
	isDisable := mcj.Status == entity.MachineCronJobStatusDisable
 | 
						isDisable := mcj.Status == entity.MachineCronJobStatusDisable
 | 
				
			||||||
	if mcj.Id == 0 {
 | 
						if mcj.Id == 0 {
 | 
				
			||||||
		key = utils.RandString(16)
 | 
							key = stringx.Rand(16)
 | 
				
			||||||
		mcj.Key = key
 | 
							mcj.Key = key
 | 
				
			||||||
		if isDisable {
 | 
							if isDisable {
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
@@ -201,11 +203,19 @@ func (m *machineCropJobAppImpl) addCronJob(mcj *entity.MachineCronJob) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	scheduler.AddFunByKey(key, mcj.Cron, func() {
 | 
						scheduler.AddFunByKey(key, mcj.Cron, func() {
 | 
				
			||||||
		m.runCronJob(key)
 | 
							go m.runCronJob(key)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *machineCropJobAppImpl) runCronJob(key string) {
 | 
					func (m *machineCropJobAppImpl) runCronJob(key string) {
 | 
				
			||||||
 | 
						// 简单使用redis分布式锁防止多实例同一时刻重复执行
 | 
				
			||||||
 | 
						if lock := rediscli.NewLock(key, 30*time.Second); lock != nil {
 | 
				
			||||||
 | 
							if !lock.Lock() {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							defer lock.UnLock()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cronJob := new(entity.MachineCronJob)
 | 
						cronJob := new(entity.MachineCronJob)
 | 
				
			||||||
	cronJob.Key = key
 | 
						cronJob.Key = key
 | 
				
			||||||
	err := m.machineCropJobRepo.GetBy(cronJob)
 | 
						err := m.machineCropJobRepo.GetBy(cronJob)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ package machine
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -69,7 +69,7 @@ func TestTemplateRev(t *testing.T) {
 | 
				
			|||||||
	//key := temp[index+1 : ei-1]
 | 
						//key := temp[index+1 : ei-1]
 | 
				
			||||||
	//value := SubString(str, index, UnicodeIndex(str, next))
 | 
						//value := SubString(str, index, UnicodeIndex(str, next))
 | 
				
			||||||
	res := make(map[string]any)
 | 
						res := make(map[string]any)
 | 
				
			||||||
	utils.ReverStrTemplate(temp, str, res)
 | 
						stringx.ReverStrTemplate(temp, str, res)
 | 
				
			||||||
	fmt.Println(res)
 | 
						fmt.Println(res)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ import (
 | 
				
			|||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"mayfly-go/pkg/global"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
	"mayfly-go/pkg/scheduler"
 | 
						"mayfly-go/pkg/scheduler"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/netx"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
@@ -75,7 +75,7 @@ func (stm *SshTunnelMachine) OpenSshTunnel(id uint64, ip string, port int) (expo
 | 
				
			|||||||
	stm.mutex.Lock()
 | 
						stm.mutex.Lock()
 | 
				
			||||||
	defer stm.mutex.Unlock()
 | 
						defer stm.mutex.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	localPort, err := utils.GetAvailablePort()
 | 
						localPort, err := netx.GetAvailablePort()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", 0, err
 | 
							return "", 0, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/biz"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/pkg/gormx"
 | 
						"mayfly-go/pkg/gormx"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/collx"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -29,7 +29,7 @@ func (m *machineRepoImpl) GetMachineList(condition *entity.MachineQuery, pagePar
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if condition.Ids != "" {
 | 
						if condition.Ids != "" {
 | 
				
			||||||
		// ,分割id转为id数组
 | 
							// ,分割id转为id数组
 | 
				
			||||||
		qd.In("id", utils.ArrayMap[string, uint64](strings.Split(condition.Ids, ","), func(val string) uint64 {
 | 
							qd.In("id", collx.ArrayMap[string, uint64](strings.Split(condition.Ids, ","), func(val string) uint64 {
 | 
				
			||||||
			id, _ := strconv.Atoi(val)
 | 
								id, _ := strconv.Atoi(val)
 | 
				
			||||||
			return uint64(id)
 | 
								return uint64(id)
 | 
				
			||||||
		}))
 | 
							}))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,8 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/cache"
 | 
						"mayfly-go/pkg/cache"
 | 
				
			||||||
	"mayfly-go/pkg/global"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/netx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/structx"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -201,7 +202,7 @@ func connect(me *entity.Mongo) (*MongoInstance, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func toMongiInfo(me *entity.Mongo) *MongoInfo {
 | 
					func toMongiInfo(me *entity.Mongo) *MongoInfo {
 | 
				
			||||||
	mi := new(MongoInfo)
 | 
						mi := new(MongoInfo)
 | 
				
			||||||
	utils.Copy(mi, me)
 | 
						structx.Copy(mi, me)
 | 
				
			||||||
	return mi
 | 
						return mi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -212,7 +213,7 @@ type MongoSshDialer struct {
 | 
				
			|||||||
func (sd *MongoSshDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
 | 
					func (sd *MongoSshDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
 | 
				
			||||||
	if sshConn, err := machineapp.GetMachineApp().GetSshTunnelMachine(sd.machineId).GetDialConn(network, address); err == nil {
 | 
						if sshConn, err := machineapp.GetMachineApp().GetSshTunnelMachine(sd.machineId).GetDialConn(network, address); err == nil {
 | 
				
			||||||
		// 将ssh conn包装,否则内部部设置超时会报错,ssh conn不支持设置超时会返回错误: ssh: tcpChan: deadline not supported
 | 
							// 将ssh conn包装,否则内部部设置超时会报错,ssh conn不支持设置超时会返回错误: ssh: tcpChan: deadline not supported
 | 
				
			||||||
		return &utils.WrapSshConn{Conn: sshConn}, nil
 | 
							return &netx.WrapSshConn{Conn: sshConn}, nil
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,8 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/ginx"
 | 
						"mayfly-go/pkg/ginx"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/req"
 | 
						"mayfly-go/pkg/req"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/cryptox"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,7 +48,7 @@ func (r *Redis) Save(rc *req.Ctx) {
 | 
				
			|||||||
	redis := ginx.BindJsonAndCopyTo[*entity.Redis](rc.GinCtx, form, new(entity.Redis))
 | 
						redis := ginx.BindJsonAndCopyTo[*entity.Redis](rc.GinCtx, form, new(entity.Redis))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 密码解密,并使用解密后的赋值
 | 
						// 密码解密,并使用解密后的赋值
 | 
				
			||||||
	originPwd, err := utils.DefaultRsaDecrypt(redis.Password, true)
 | 
						originPwd, err := cryptox.DefaultRsaDecrypt(redis.Password, true)
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "解密密码错误: %s")
 | 
						biz.ErrIsNilAppendErr(err, "解密密码错误: %s")
 | 
				
			||||||
	redis.Password = originPwd
 | 
						redis.Password = originPwd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -133,7 +134,7 @@ func (r *Redis) RedisInfo(rc *req.Ctx) {
 | 
				
			|||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if strings.Contains(datas[i], "#") {
 | 
							if strings.Contains(datas[i], "#") {
 | 
				
			||||||
			key := utils.SubString(datas[i], strings.Index(datas[i], "#")+1, utils.StrLen(datas[i]))
 | 
								key := stringx.SubString(datas[i], strings.Index(datas[i], "#")+1, stringx.Len(datas[i]))
 | 
				
			||||||
			i++
 | 
								i++
 | 
				
			||||||
			key = strings.Trim(key, " ")
 | 
								key = strings.Trim(key, " ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/biz"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/pkg/ginx"
 | 
						"mayfly-go/pkg/ginx"
 | 
				
			||||||
	"mayfly-go/pkg/req"
 | 
						"mayfly-go/pkg/req"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,7 +25,7 @@ func (r *Redis) SetStringValue(rc *req.Ctx) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ri := r.getRedisIns(rc)
 | 
						ri := r.getRedisIns(rc)
 | 
				
			||||||
	cmd := ri.GetCmdable()
 | 
						cmd := ri.GetCmdable()
 | 
				
			||||||
	rc.ReqParam = fmt.Sprintf("%s -> %s", ri.Info.GetLogDesc(), utils.ToString(keyValue))
 | 
						rc.ReqParam = fmt.Sprintf("%s -> %s", ri.Info.GetLogDesc(), stringx.AnyToStr(keyValue))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	str, err := cmd.Set(context.TODO(), keyValue.Key, keyValue.Value, time.Second*time.Duration(keyValue.Timed)).Result()
 | 
						str, err := cmd.Set(context.TODO(), keyValue.Key, keyValue.Value, time.Second*time.Duration(keyValue.Timed)).Result()
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "保存字符串值失败: %s")
 | 
						biz.ErrIsNilAppendErr(err, "保存字符串值失败: %s")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,8 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/cache"
 | 
						"mayfly-go/pkg/cache"
 | 
				
			||||||
	"mayfly-go/pkg/global"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/netx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/structx"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@@ -176,7 +177,7 @@ func getRedisCacheKey(id uint64, db int) string {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func toRedisInfo(re *entity.Redis, db int) *RedisInfo {
 | 
					func toRedisInfo(re *entity.Redis, db int) *RedisInfo {
 | 
				
			||||||
	redisInfo := new(RedisInfo)
 | 
						redisInfo := new(RedisInfo)
 | 
				
			||||||
	utils.Copy(redisInfo, re)
 | 
						structx.Copy(redisInfo, re)
 | 
				
			||||||
	redisInfo.Db = db
 | 
						redisInfo.Db = db
 | 
				
			||||||
	return redisInfo
 | 
						return redisInfo
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -243,7 +244,7 @@ func getRedisDialer(machineId int) func(ctx context.Context, network, addr strin
 | 
				
			|||||||
	return func(_ context.Context, network, addr string) (net.Conn, error) {
 | 
						return func(_ context.Context, network, addr string) (net.Conn, error) {
 | 
				
			||||||
		if sshConn, err := sshTunnel.GetDialConn(network, addr); err == nil {
 | 
							if sshConn, err := sshTunnel.GetDialConn(network, addr); err == nil {
 | 
				
			||||||
			// 将ssh conn包装,否则redis内部设置超时会报错,ssh conn不支持设置超时会返回错误: ssh: tcpChan: deadline not supported
 | 
								// 将ssh conn包装,否则redis内部设置超时会报错,ssh conn不支持设置超时会返回错误: ssh: tcpChan: deadline not supported
 | 
				
			||||||
			return &utils.WrapSshConn{Conn: sshConn}, nil
 | 
								return &netx.WrapSshConn{Conn: sshConn}, nil
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,12 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/otp"
 | 
						"mayfly-go/pkg/otp"
 | 
				
			||||||
	"mayfly-go/pkg/req"
 | 
						"mayfly-go/pkg/req"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/collx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/cryptox"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/jsonx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/netx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/timex"
 | 
				
			||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@@ -55,7 +60,7 @@ func (a *Account) Login(rc *req.Ctx) {
 | 
				
			|||||||
	clientIp := getIpAndRegion(rc)
 | 
						clientIp := getIpAndRegion(rc)
 | 
				
			||||||
	rc.ReqParam = fmt.Sprintf("username: %s | ip: %s", username, clientIp)
 | 
						rc.ReqParam = fmt.Sprintf("username: %s | ip: %s", username, clientIp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	originPwd, err := utils.DefaultRsaDecrypt(loginForm.Password, true)
 | 
						originPwd, err := cryptox.DefaultRsaDecrypt(loginForm.Password, true)
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "解密密码错误: %s")
 | 
						biz.ErrIsNilAppendErr(err, "解密密码错误: %s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	account := &entity.Account{Username: username}
 | 
						account := &entity.Account{Username: username}
 | 
				
			||||||
@@ -67,7 +72,7 @@ func (a *Account) Login(rc *req.Ctx) {
 | 
				
			|||||||
	loginFailMin := accountLoginSecurity.LoginFailMin
 | 
						loginFailMin := accountLoginSecurity.LoginFailMin
 | 
				
			||||||
	biz.IsTrue(nowFailCount < loginFailCount, "登录失败超过%d次, 请%d分钟后再试", loginFailCount, loginFailMin)
 | 
						biz.IsTrue(nowFailCount < loginFailCount, "登录失败超过%d次, 请%d分钟后再试", loginFailCount, loginFailMin)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err != nil || !utils.CheckPwdHash(originPwd, account.Password) {
 | 
						if err != nil || !cryptox.CheckPwdHash(originPwd, account.Password) {
 | 
				
			||||||
		nowFailCount++
 | 
							nowFailCount++
 | 
				
			||||||
		cache.SetStr(failCountKey, strconv.Itoa(nowFailCount), time.Minute*time.Duration(loginFailMin))
 | 
							cache.SetStr(failCountKey, strconv.Itoa(nowFailCount), time.Minute*time.Duration(loginFailMin))
 | 
				
			||||||
		panic(biz.NewBizErr(fmt.Sprintf("用户名或密码错误【当前登录失败%d次】", nowFailCount)))
 | 
							panic(biz.NewBizErr(fmt.Sprintf("用户名或密码错误【当前登录失败%d次】", nowFailCount)))
 | 
				
			||||||
@@ -96,7 +101,7 @@ func (a *Account) Login(rc *req.Ctx) {
 | 
				
			|||||||
		// 修改状态为已注册
 | 
							// 修改状态为已注册
 | 
				
			||||||
		otpStatus = OtpStatusReg
 | 
							otpStatus = OtpStatusReg
 | 
				
			||||||
		// 该token用于otp双因素校验
 | 
							// 该token用于otp双因素校验
 | 
				
			||||||
		token = utils.RandString(32)
 | 
							token = stringx.Rand(32)
 | 
				
			||||||
		// 未注册otp secret或重置了秘钥
 | 
							// 未注册otp secret或重置了秘钥
 | 
				
			||||||
		if otpSecret == "" || otpSecret == "-" {
 | 
							if otpSecret == "" || otpSecret == "-" {
 | 
				
			||||||
			otpStatus = OtpStatusNoReg
 | 
								otpStatus = OtpStatusNoReg
 | 
				
			||||||
@@ -116,7 +121,7 @@ func (a *Account) Login(rc *req.Ctx) {
 | 
				
			|||||||
			OtpSecret:   otpSecret,
 | 
								OtpSecret:   otpSecret,
 | 
				
			||||||
			AccessToken: accessToken,
 | 
								AccessToken: accessToken,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		cache.SetStr(fmt.Sprintf("otp:token:%s", token), utils.ToJsonStr(otpInfo), time.Minute*time.Duration(3))
 | 
							cache.SetStr(fmt.Sprintf("otp:token:%s", token), jsonx.ToStr(otpInfo), time.Minute*time.Duration(3))
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		// 不进行otp二次校验则直接返回accessToken
 | 
							// 不进行otp二次校验则直接返回accessToken
 | 
				
			||||||
		token = accessToken
 | 
							token = accessToken
 | 
				
			||||||
@@ -133,7 +138,7 @@ func (a *Account) Login(rc *req.Ctx) {
 | 
				
			|||||||
// 获取ip与归属地信息
 | 
					// 获取ip与归属地信息
 | 
				
			||||||
func getIpAndRegion(rc *req.Ctx) string {
 | 
					func getIpAndRegion(rc *req.Ctx) string {
 | 
				
			||||||
	clientIp := rc.GinCtx.ClientIP()
 | 
						clientIp := rc.GinCtx.ClientIP()
 | 
				
			||||||
	return fmt.Sprintf("%s %s", clientIp, utils.Ip2Region(clientIp))
 | 
						return fmt.Sprintf("%s %s", clientIp, netx.Ip2Region(clientIp))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type OtpVerifyInfo struct {
 | 
					type OtpVerifyInfo struct {
 | 
				
			||||||
@@ -214,22 +219,22 @@ func (a *Account) ChangePassword(rc *req.Ctx) {
 | 
				
			|||||||
	form := new(form.AccountChangePasswordForm)
 | 
						form := new(form.AccountChangePasswordForm)
 | 
				
			||||||
	ginx.BindJsonAndValid(rc.GinCtx, form)
 | 
						ginx.BindJsonAndValid(rc.GinCtx, form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	originOldPwd, err := utils.DefaultRsaDecrypt(form.OldPassword, true)
 | 
						originOldPwd, err := cryptox.DefaultRsaDecrypt(form.OldPassword, true)
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "解密旧密码错误: %s")
 | 
						biz.ErrIsNilAppendErr(err, "解密旧密码错误: %s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	account := &entity.Account{Username: form.Username}
 | 
						account := &entity.Account{Username: form.Username}
 | 
				
			||||||
	err = a.AccountApp.GetAccount(account, "Id", "Username", "Password", "Status")
 | 
						err = a.AccountApp.GetAccount(account, "Id", "Username", "Password", "Status")
 | 
				
			||||||
	biz.ErrIsNil(err, "旧密码错误")
 | 
						biz.ErrIsNil(err, "旧密码错误")
 | 
				
			||||||
	biz.IsTrue(utils.CheckPwdHash(originOldPwd, account.Password), "旧密码错误")
 | 
						biz.IsTrue(cryptox.CheckPwdHash(originOldPwd, account.Password), "旧密码错误")
 | 
				
			||||||
	biz.IsTrue(account.IsEnable(), "该账号不可用")
 | 
						biz.IsTrue(account.IsEnable(), "该账号不可用")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	originNewPwd, err := utils.DefaultRsaDecrypt(form.NewPassword, true)
 | 
						originNewPwd, err := cryptox.DefaultRsaDecrypt(form.NewPassword, true)
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "解密新密码错误: %s")
 | 
						biz.ErrIsNilAppendErr(err, "解密新密码错误: %s")
 | 
				
			||||||
	biz.IsTrue(CheckPasswordLever(originNewPwd), "密码强度必须8位以上且包含字⺟⼤⼩写+数字+特殊符号")
 | 
						biz.IsTrue(CheckPasswordLever(originNewPwd), "密码强度必须8位以上且包含字⺟⼤⼩写+数字+特殊符号")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	updateAccount := new(entity.Account)
 | 
						updateAccount := new(entity.Account)
 | 
				
			||||||
	updateAccount.Id = account.Id
 | 
						updateAccount.Id = account.Id
 | 
				
			||||||
	updateAccount.Password = utils.PwdHash(originNewPwd)
 | 
						updateAccount.Password = cryptox.PwdHash(originNewPwd)
 | 
				
			||||||
	a.AccountApp.Update(updateAccount)
 | 
						a.AccountApp.Update(updateAccount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 赋值loginAccount 主要用于记录操作日志,因为操作日志保存请求上下文没有该信息不保存日志
 | 
						// 赋值loginAccount 主要用于记录操作日志,因为操作日志保存请求上下文没有该信息不保存日志
 | 
				
			||||||
@@ -267,7 +272,7 @@ func (a *Account) saveLogin(account *entity.Account, ip string) {
 | 
				
			|||||||
	// 创建登录消息
 | 
						// 创建登录消息
 | 
				
			||||||
	loginMsg := &msgentity.Msg{
 | 
						loginMsg := &msgentity.Msg{
 | 
				
			||||||
		RecipientId: int64(account.Id),
 | 
							RecipientId: int64(account.Id),
 | 
				
			||||||
		Msg:         fmt.Sprintf("于[%s]-[%s]登录", ip, utils.DefaultTimeFormat(now)),
 | 
							Msg:         fmt.Sprintf("于[%s]-[%s]登录", ip, timex.DefaultFormat(now)),
 | 
				
			||||||
		Type:        1,
 | 
							Type:        1,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	loginMsg.CreateTime = &now
 | 
						loginMsg.CreateTime = &now
 | 
				
			||||||
@@ -295,7 +300,7 @@ func (a *Account) UpdateAccount(rc *req.Ctx) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if updateAccount.Password != "" {
 | 
						if updateAccount.Password != "" {
 | 
				
			||||||
		biz.IsTrue(CheckPasswordLever(updateAccount.Password), "密码强度必须8位以上且包含字⺟⼤⼩写+数字+特殊符号")
 | 
							biz.IsTrue(CheckPasswordLever(updateAccount.Password), "密码强度必须8位以上且包含字⺟⼤⼩写+数字+特殊符号")
 | 
				
			||||||
		updateAccount.Password = utils.PwdHash(updateAccount.Password)
 | 
							updateAccount.Password = cryptox.PwdHash(updateAccount.Password)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	a.AccountApp.Update(updateAccount)
 | 
						a.AccountApp.Update(updateAccount)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -323,7 +328,7 @@ func (a *Account) SaveAccount(rc *req.Ctx) {
 | 
				
			|||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if account.Password != "" {
 | 
							if account.Password != "" {
 | 
				
			||||||
			biz.IsTrue(CheckPasswordLever(account.Password), "密码强度必须8位以上且包含字⺟⼤⼩写+数字+特殊符号")
 | 
								biz.IsTrue(CheckPasswordLever(account.Password), "密码强度必须8位以上且包含字⺟⼤⼩写+数字+特殊符号")
 | 
				
			||||||
			account.Password = utils.PwdHash(account.Password)
 | 
								account.Password = cryptox.PwdHash(account.Password)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		a.AccountApp.Update(account)
 | 
							a.AccountApp.Update(account)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -380,14 +385,14 @@ func (a *Account) SaveRoles(rc *req.Ctx) {
 | 
				
			|||||||
	rc.ReqParam = form
 | 
						rc.ReqParam = form
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 将,拼接的字符串进行切割并转换
 | 
						// 将,拼接的字符串进行切割并转换
 | 
				
			||||||
	newIds := utils.ArrayMap[string, uint64](strings.Split(form.RoleIds, ","), func(val string) uint64 {
 | 
						newIds := collx.ArrayMap[string, uint64](strings.Split(form.RoleIds, ","), func(val string) uint64 {
 | 
				
			||||||
		id, _ := strconv.Atoi(val)
 | 
							id, _ := strconv.Atoi(val)
 | 
				
			||||||
		return uint64(id)
 | 
							return uint64(id)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	oIds := a.RoleApp.GetAccountRoleIds(uint64(form.Id))
 | 
						oIds := a.RoleApp.GetAccountRoleIds(uint64(form.Id))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addIds, delIds, _ := utils.ArrayCompare(newIds, oIds, func(i1, i2 uint64) bool {
 | 
						addIds, delIds, _ := collx.ArrayCompare(newIds, oIds, func(i1, i2 uint64) bool {
 | 
				
			||||||
		return i1 == i2
 | 
							return i1 == i2
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/ginx"
 | 
						"mayfly-go/pkg/ginx"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/req"
 | 
						"mayfly-go/pkg/req"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/collx"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -72,14 +72,14 @@ func (r *Role) SaveResource(rc *req.Ctx) {
 | 
				
			|||||||
	rc.ReqParam = form
 | 
						rc.ReqParam = form
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 将,拼接的字符串进行切割并转换
 | 
						// 将,拼接的字符串进行切割并转换
 | 
				
			||||||
	newIds := utils.ArrayMap[string, uint64](strings.Split(form.ResourceIds, ","), func(val string) uint64 {
 | 
						newIds := collx.ArrayMap[string, uint64](strings.Split(form.ResourceIds, ","), func(val string) uint64 {
 | 
				
			||||||
		id, _ := strconv.Atoi(val)
 | 
							id, _ := strconv.Atoi(val)
 | 
				
			||||||
		return uint64(id)
 | 
							return uint64(id)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	oIds := r.RoleApp.GetRoleResourceIds(uint64(form.Id))
 | 
						oIds := r.RoleApp.GetRoleResourceIds(uint64(form.Id))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addIds, delIds, _ := utils.ArrayCompare(newIds, oIds, func(i1, i2 uint64) bool {
 | 
						addIds, delIds, _ := collx.ArrayCompare(newIds, oIds, func(i1, i2 uint64) bool {
 | 
				
			||||||
		return i1 == i2
 | 
							return i1 == i2
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/biz"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/pkg/gormx"
 | 
						"mayfly-go/pkg/gormx"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/cryptox"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gorm.io/gorm"
 | 
						"gorm.io/gorm"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -45,7 +45,7 @@ func (a *accountAppImpl) GetPageList(condition *entity.Account, pageParam *model
 | 
				
			|||||||
func (a *accountAppImpl) Create(account *entity.Account) {
 | 
					func (a *accountAppImpl) Create(account *entity.Account) {
 | 
				
			||||||
	biz.IsTrue(a.GetAccount(&entity.Account{Username: account.Username}) != nil, "该账号用户名已存在")
 | 
						biz.IsTrue(a.GetAccount(&entity.Account{Username: account.Username}) != nil, "该账号用户名已存在")
 | 
				
			||||||
	// 默认密码为账号用户名
 | 
						// 默认密码为账号用户名
 | 
				
			||||||
	account.Password = utils.PwdHash(account.Username)
 | 
						account.Password = cryptox.PwdHash(account.Username)
 | 
				
			||||||
	account.Status = entity.AccountEnableStatus
 | 
						account.Status = entity.AccountEnableStatus
 | 
				
			||||||
	a.accountRepo.Insert(account)
 | 
						a.accountRepo.Insert(account)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/cache"
 | 
						"mayfly-go/pkg/cache"
 | 
				
			||||||
	"mayfly-go/pkg/global"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/jsonx"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const SysConfigKeyPrefix = "sys:config:"
 | 
					const SysConfigKeyPrefix = "sys:config:"
 | 
				
			||||||
@@ -56,7 +56,7 @@ func (a *configAppImpl) GetConfig(key string) *entity.Config {
 | 
				
			|||||||
	if err := a.configRepo.GetConfig(config, "Id", "Key", "Value"); err != nil {
 | 
						if err := a.configRepo.GetConfig(config, "Id", "Key", "Value"); err != nil {
 | 
				
			||||||
		global.Log.Warnf("不存在key = [%s] 的系统配置", key)
 | 
							global.Log.Warnf("不存在key = [%s] 的系统配置", key)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		cache.SetStr(SysConfigKeyPrefix+key, utils.ToJsonStr(config), -1)
 | 
							cache.SetStr(SysConfigKeyPrefix+key, jsonx.ToStr(config), -1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return config
 | 
						return config
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/internal/sys/domain/repository"
 | 
						"mayfly-go/internal/sys/domain/repository"
 | 
				
			||||||
	"mayfly-go/pkg/biz"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/pkg/gormx"
 | 
						"mayfly-go/pkg/gormx"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -59,7 +59,7 @@ func (r *resourceAppImpl) Save(resource *entity.Resource) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 生成随机八位唯一标识符
 | 
						// 生成随机八位唯一标识符
 | 
				
			||||||
	ui := utils.RandString(8)
 | 
						ui := stringx.Rand(8)
 | 
				
			||||||
	if pid := resource.Pid; pid != 0 {
 | 
						if pid := resource.Pid; pid != 0 {
 | 
				
			||||||
		pResource := r.GetById(uint64(pid))
 | 
							pResource := r.GetById(uint64(pid))
 | 
				
			||||||
		biz.IsTrue(pResource != nil, "该父资源不存在")
 | 
							biz.IsTrue(pResource != nil, "该父资源不存在")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/biz"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/req"
 | 
						"mayfly-go/pkg/req"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/anyx"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -50,7 +50,7 @@ func (m *syslogAppImpl) SaveFromReq(req *req.Ctx) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reqParam := req.ReqParam
 | 
						reqParam := req.ReqParam
 | 
				
			||||||
	if !utils.IsBlank(reqParam) {
 | 
						if !anyx.IsBlank(reqParam) {
 | 
				
			||||||
		// 如果是字符串类型,则不使用json序列化
 | 
							// 如果是字符串类型,则不使用json序列化
 | 
				
			||||||
		if reqStr, ok := reqParam.(string); ok {
 | 
							if reqStr, ok := reqParam.(string); ok {
 | 
				
			||||||
			syslog.ReqParam = reqStr
 | 
								syslog.ReqParam = reqStr
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/biz"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/pkg/ginx"
 | 
						"mayfly-go/pkg/ginx"
 | 
				
			||||||
	"mayfly-go/pkg/req"
 | 
						"mayfly-go/pkg/req"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/collx"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -125,7 +125,7 @@ func (p *Team) SaveTags(rc *req.Ctx) {
 | 
				
			|||||||
	oIds := p.TeamApp.ListTagIds(teamId)
 | 
						oIds := p.TeamApp.ListTagIds(teamId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 比较新旧两合集
 | 
						// 比较新旧两合集
 | 
				
			||||||
	addIds, delIds, _ := utils.ArrayCompare(form.TagIds, oIds, func(i1, i2 uint64) bool {
 | 
						addIds, delIds, _ := collx.ArrayCompare(form.TagIds, oIds, func(i1, i2 uint64) bool {
 | 
				
			||||||
		return i1 == i2
 | 
							return i1 == i2
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -253,7 +253,7 @@ CREATE TABLE `t_machine_cron_job` (
 | 
				
			|||||||
  `modifier` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
 | 
					  `modifier` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
 | 
				
			||||||
  `create_time` datetime DEFAULT NULL,
 | 
					  `create_time` datetime DEFAULT NULL,
 | 
				
			||||||
  `update_time` datetime DEFAULT NULL,
 | 
					  `update_time` datetime DEFAULT NULL,
 | 
				
			||||||
  `is_deleted` tinyint NOT NULL DEFAULT '-1',
 | 
					  `is_deleted` tinyint NOT NULL DEFAULT 0,
 | 
				
			||||||
  `delete_time` datetime DEFAULT NULL,
 | 
					  `delete_time` datetime DEFAULT NULL,
 | 
				
			||||||
  PRIMARY KEY (`id`)
 | 
					  PRIMARY KEY (`id`)
 | 
				
			||||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='机器计划任务';
 | 
					) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='机器计划任务';
 | 
				
			||||||
@@ -266,7 +266,7 @@ CREATE TABLE `t_machine_cron_job_exec` (
 | 
				
			|||||||
  `status` tinyint DEFAULT NULL COMMENT '状态',
 | 
					  `status` tinyint DEFAULT NULL COMMENT '状态',
 | 
				
			||||||
  `res` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '执行结果',
 | 
					  `res` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '执行结果',
 | 
				
			||||||
  `exec_time` datetime DEFAULT NULL COMMENT '执行时间',
 | 
					  `exec_time` datetime DEFAULT NULL COMMENT '执行时间',
 | 
				
			||||||
  `is_deleted` tinyint NOT NULL DEFAULT '-1',
 | 
					  `is_deleted` tinyint NOT NULL DEFAULT 0,
 | 
				
			||||||
  `delete_time` datetime DEFAULT NULL,
 | 
					  `delete_time` datetime DEFAULT NULL,
 | 
				
			||||||
  PRIMARY KEY (`id`)
 | 
					  PRIMARY KEY (`id`)
 | 
				
			||||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='机器计划任务执行记录';
 | 
					) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='机器计划任务执行记录';
 | 
				
			||||||
@@ -279,7 +279,7 @@ CREATE TABLE `t_machine_cron_job_relate` (
 | 
				
			|||||||
  `creator_id` bigint DEFAULT NULL,
 | 
					  `creator_id` bigint DEFAULT NULL,
 | 
				
			||||||
  `creator` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
 | 
					  `creator` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
 | 
				
			||||||
  `create_time` datetime DEFAULT NULL,
 | 
					  `create_time` datetime DEFAULT NULL,
 | 
				
			||||||
  `is_deleted` tinyint NOT NULL DEFAULT '-1',
 | 
					  `is_deleted` tinyint NOT NULL DEFAULT 0,
 | 
				
			||||||
  `delete_time` datetime DEFAULT NULL,
 | 
					  `delete_time` datetime DEFAULT NULL,
 | 
				
			||||||
  PRIMARY KEY (`id`)
 | 
					  PRIMARY KEY (`id`)
 | 
				
			||||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='机器计划任务关联表';
 | 
					) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='机器计划任务关联表';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ package biz
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/pkg/global"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/anyx"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -56,7 +56,7 @@ func NotNil(data any, msg string, params ...any) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NotBlank(data any, msg string, params ...any) {
 | 
					func NotBlank(data any, msg string, params ...any) {
 | 
				
			||||||
	if utils.IsBlank(data) {
 | 
						if anyx.IsBlank(data) {
 | 
				
			||||||
		panic(NewBizErr(fmt.Sprintf(msg, params...)))
 | 
							panic(NewBizErr(fmt.Sprintf(msg, params...)))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,8 +2,8 @@ package config
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
					 | 
				
			||||||
	"mayfly-go/pkg/utils/assert"
 | 
						"mayfly-go/pkg/utils/assert"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/cryptox"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Aes struct {
 | 
					type Aes struct {
 | 
				
			||||||
@@ -12,12 +12,12 @@ type Aes struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// 编码并base64
 | 
					// 编码并base64
 | 
				
			||||||
func (a *Aes) EncryptBase64(data []byte) (string, error) {
 | 
					func (a *Aes) EncryptBase64(data []byte) (string, error) {
 | 
				
			||||||
	return utils.AesEncryptBase64(data, []byte(a.Key))
 | 
						return cryptox.AesEncryptBase64(data, []byte(a.Key))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// base64解码后再aes解码
 | 
					// base64解码后再aes解码
 | 
				
			||||||
func (a *Aes) DecryptBase64(data string) ([]byte, error) {
 | 
					func (a *Aes) DecryptBase64(data string) ([]byte, error) {
 | 
				
			||||||
	return utils.AesDecryptBase64(data, []byte(a.Key))
 | 
						return cryptox.AesDecryptBase64(data, []byte(a.Key))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (j *Aes) Valid() {
 | 
					func (j *Aes) Valid() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,8 +3,8 @@ package config
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"flag"
 | 
						"flag"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
					 | 
				
			||||||
	"mayfly-go/pkg/utils/assert"
 | 
						"mayfly-go/pkg/utils/assert"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/ymlx"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -20,7 +20,7 @@ func Init() {
 | 
				
			|||||||
	startConfigParam := &CmdConfigParam{ConfigFilePath: path}
 | 
						startConfigParam := &CmdConfigParam{ConfigFilePath: path}
 | 
				
			||||||
	// 读取配置文件信息
 | 
						// 读取配置文件信息
 | 
				
			||||||
	yc := &Config{}
 | 
						yc := &Config{}
 | 
				
			||||||
	if err := utils.LoadYml(startConfigParam.ConfigFilePath, yc); err != nil {
 | 
						if err := ymlx.LoadYml(startConfigParam.ConfigFilePath, yc); err != nil {
 | 
				
			||||||
		panic(fmt.Sprintf("读取配置文件[%s]失败: %s", startConfigParam.ConfigFilePath, err.Error()))
 | 
							panic(fmt.Sprintf("读取配置文件[%s]失败: %s", startConfigParam.ConfigFilePath, err.Error()))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// 校验配置文件内容信息
 | 
						// 校验配置文件内容信息
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/biz"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/pkg/global"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/structx"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"runtime/debug"
 | 
						"runtime/debug"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
@@ -25,7 +25,7 @@ func BindJsonAndValid[T any](g *gin.Context, data T) T {
 | 
				
			|||||||
// 绑定请求体中的json至form结构体,并拷贝至另一结构体
 | 
					// 绑定请求体中的json至form结构体,并拷贝至另一结构体
 | 
				
			||||||
func BindJsonAndCopyTo[T any](g *gin.Context, form any, toStruct T) T {
 | 
					func BindJsonAndCopyTo[T any](g *gin.Context, form any, toStruct T) T {
 | 
				
			||||||
	BindJsonAndValid(g, form)
 | 
						BindJsonAndValid(g, form)
 | 
				
			||||||
	utils.Copy(toStruct, form)
 | 
						structx.Copy(toStruct, form)
 | 
				
			||||||
	return toStruct
 | 
						return toStruct
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/consts"
 | 
						"mayfly-go/pkg/consts"
 | 
				
			||||||
	"mayfly-go/pkg/global"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/anyx"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gorm.io/gorm"
 | 
						"gorm.io/gorm"
 | 
				
			||||||
@@ -159,7 +159,7 @@ func (q *QueryCond) Le(column string, val any) *QueryCond {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (q *QueryCond) Cond(cond, column string, val any, skipBlank bool) *QueryCond {
 | 
					func (q *QueryCond) Cond(cond, column string, val any, skipBlank bool) *QueryCond {
 | 
				
			||||||
	// 零值跳过
 | 
						// 零值跳过
 | 
				
			||||||
	if skipBlank && utils.IsBlank(val) {
 | 
						if skipBlank && anyx.IsBlank(val) {
 | 
				
			||||||
		return q
 | 
							return q
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	q.columns = append(q.columns, fmt.Sprintf("%s %s ?", column, cond))
 | 
						q.columns = append(q.columns, fmt.Sprintf("%s %s ?", column, cond))
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										96
									
								
								server/pkg/rediscli/lock.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								server/pkg/rediscli/lock.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					package rediscli
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/redis/go-redis/v9"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const LockKeyPrefix = "mayfly:lock:"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RedisLock redis实现的分布式锁
 | 
				
			||||||
 | 
					type RedisLock struct {
 | 
				
			||||||
 | 
						key        string
 | 
				
			||||||
 | 
						value      string // 唯一标识,一般使用uuid
 | 
				
			||||||
 | 
						expiration time.Duration
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewLock(key string, expiration time.Duration) *RedisLock {
 | 
				
			||||||
 | 
						if key == "" || cli == nil {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &RedisLock{
 | 
				
			||||||
 | 
							key:        key,
 | 
				
			||||||
 | 
							value:      stringx.Rand(32),
 | 
				
			||||||
 | 
							expiration: expiration,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Lock 添加分布式锁,expiration过期时间,小于等于0,不过期,需要通过 UnLock方法释放锁
 | 
				
			||||||
 | 
					func (rl *RedisLock) Lock() bool {
 | 
				
			||||||
 | 
						result, err := cli.SetNX(context.Background(), LockKeyPrefix+rl.key, rl.value, rl.expiration).Result()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							global.Log.Errorf("redis lock setNx fail: %s", err.Error())
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TryLock 加锁重试五次
 | 
				
			||||||
 | 
					func (rl *RedisLock) TryLock() bool {
 | 
				
			||||||
 | 
						var locked bool
 | 
				
			||||||
 | 
						for index := 0; index < 5; index++ {
 | 
				
			||||||
 | 
							locked = rl.Lock()
 | 
				
			||||||
 | 
							if locked {
 | 
				
			||||||
 | 
								return locked
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							time.Sleep(50 * time.Millisecond)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return locked
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (rl *RedisLock) UnLock() bool {
 | 
				
			||||||
 | 
						script := redis.NewScript(`
 | 
				
			||||||
 | 
						if redis.call("get", KEYS[1]) == ARGV[1] then
 | 
				
			||||||
 | 
							return redis.call("del", KEYS[1])
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result, err := script.Run(context.Background(), cli, []string{LockKeyPrefix + rl.key}, rl.value).Int64()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							global.Log.Errorf("redis unlock runScript fail: %s", err.Error())
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result > 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RefreshLock 存在则更新过期时间,不存在则创建key
 | 
				
			||||||
 | 
					func (rl *RedisLock) RefreshLock() bool {
 | 
				
			||||||
 | 
						script := redis.NewScript(`
 | 
				
			||||||
 | 
						local val = redis.call("GET", KEYS[1])
 | 
				
			||||||
 | 
						if not val then
 | 
				
			||||||
 | 
							redis.call("setex", KEYS[1], ARGV[2], ARGV[1])
 | 
				
			||||||
 | 
							return 2
 | 
				
			||||||
 | 
						elseif val == ARGV[1] then
 | 
				
			||||||
 | 
							return redis.call("expire", KEYS[1], ARGV[2])
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result, err := script.Run(context.Background(), cli, []string{LockKeyPrefix + rl.key}, rl.value, rl.expiration/time.Second).Int64()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							global.Log.Errorf("redis refreshLock runScript fail: %s", err.Error())
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result > 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,7 +4,8 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/pkg/biz"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/pkg/logger"
 | 
						"mayfly-go/pkg/logger"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/anyx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -72,21 +73,21 @@ func LogHandler(rc *Ctx) error {
 | 
				
			|||||||
func getLogMsg(rc *Ctx) string {
 | 
					func getLogMsg(rc *Ctx) string {
 | 
				
			||||||
	logInfo := rc.Conf.logInfo
 | 
						logInfo := rc.Conf.logInfo
 | 
				
			||||||
	msg := logInfo.Description + fmt.Sprintf(" ->%dms", rc.timed)
 | 
						msg := logInfo.Description + fmt.Sprintf(" ->%dms", rc.timed)
 | 
				
			||||||
	if !utils.IsBlank(rc.ReqParam) {
 | 
						if !anyx.IsBlank(rc.ReqParam) {
 | 
				
			||||||
		msg = msg + fmt.Sprintf("\n--> %s", utils.ToString(rc.ReqParam))
 | 
							msg = msg + fmt.Sprintf("\n--> %s", stringx.AnyToStr(rc.ReqParam))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 返回结果不为空,则记录返回结果
 | 
						// 返回结果不为空,则记录返回结果
 | 
				
			||||||
	if logInfo.LogResp && !utils.IsBlank(rc.ResData) {
 | 
						if logInfo.LogResp && !anyx.IsBlank(rc.ResData) {
 | 
				
			||||||
		msg = msg + fmt.Sprintf("\n<-- %s", utils.ToString(rc.ResData))
 | 
							msg = msg + fmt.Sprintf("\n<-- %s", stringx.AnyToStr(rc.ResData))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return msg
 | 
						return msg
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getErrMsg(rc *Ctx, err any) string {
 | 
					func getErrMsg(rc *Ctx, err any) string {
 | 
				
			||||||
	msg := rc.Conf.logInfo.Description
 | 
						msg := rc.Conf.logInfo.Description
 | 
				
			||||||
	if !utils.IsBlank(rc.ReqParam) {
 | 
						if !anyx.IsBlank(rc.ReqParam) {
 | 
				
			||||||
		msg = msg + fmt.Sprintf("\n--> %s", utils.ToString(rc.ReqParam))
 | 
							msg = msg + fmt.Sprintf("\n--> %s", stringx.AnyToStr(rc.ReqParam))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var errMsg string
 | 
						var errMsg string
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/cache"
 | 
						"mayfly-go/pkg/cache"
 | 
				
			||||||
	"mayfly-go/pkg/config"
 | 
						"mayfly-go/pkg/config"
 | 
				
			||||||
	"mayfly-go/pkg/rediscli"
 | 
						"mayfly-go/pkg/rediscli"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -124,7 +124,7 @@ type RedisPermissionCodeRegistry struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *RedisPermissionCodeRegistry) SaveCodes(userId uint64, codes []string) {
 | 
					func (r *RedisPermissionCodeRegistry) SaveCodes(userId uint64, codes []string) {
 | 
				
			||||||
	rediscli.Set(fmt.Sprintf("mayfly:%v:codes", userId), utils.ToString(codes), time.Minute*time.Duration(config.Conf.Jwt.ExpireTime))
 | 
						rediscli.Set(fmt.Sprintf("mayfly:%v:codes", userId), stringx.AnyToStr(codes), time.Minute*time.Duration(config.Conf.Jwt.ExpireTime))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *RedisPermissionCodeRegistry) HasCode(userId uint64, code string) bool {
 | 
					func (r *RedisPermissionCodeRegistry) HasCode(userId uint64, code string) bool {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/config"
 | 
						"mayfly-go/pkg/config"
 | 
				
			||||||
	"mayfly-go/pkg/global"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/utils"
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/golang-jwt/jwt/v5"
 | 
						"github.com/golang-jwt/jwt/v5"
 | 
				
			||||||
@@ -35,7 +35,7 @@ func CreateToken(userId uint64, username string) string {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// 如果配置文件中的jwt key为空,则随机生成字符串
 | 
						// 如果配置文件中的jwt key为空,则随机生成字符串
 | 
				
			||||||
	if JwtKey == "" {
 | 
						if JwtKey == "" {
 | 
				
			||||||
		JwtKey = utils.RandString(32)
 | 
							JwtKey = stringx.Rand(32)
 | 
				
			||||||
		global.Log.Infof("config.yml未配置jwt.key, 随机生成key为: %s", JwtKey)
 | 
							global.Log.Infof("config.yml未配置jwt.key, 随机生成key为: %s", JwtKey)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// 使用自定义字符串加密 and get the complete encoded token as a string
 | 
						// 使用自定义字符串加密 and get the complete encoded token as a string
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
package starter
 | 
					package starter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"mayfly-go/initialize"
 | 
				
			||||||
	"mayfly-go/pkg/config"
 | 
						"mayfly-go/pkg/config"
 | 
				
			||||||
	"mayfly-go/pkg/logger"
 | 
						"mayfly-go/pkg/logger"
 | 
				
			||||||
	"mayfly-go/pkg/req"
 | 
						"mayfly-go/pkg/req"
 | 
				
			||||||
@@ -9,17 +10,25 @@ import (
 | 
				
			|||||||
func RunWebServer() {
 | 
					func RunWebServer() {
 | 
				
			||||||
	// 初始化config.yml配置文件映射信息
 | 
						// 初始化config.yml配置文件映射信息
 | 
				
			||||||
	config.Init()
 | 
						config.Init()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 初始化日志配置信息
 | 
						// 初始化日志配置信息
 | 
				
			||||||
	logger.Init()
 | 
						logger.Init()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 初始化jwt key与expire time等
 | 
						// 初始化jwt key与expire time等
 | 
				
			||||||
	req.InitTokenConfig()
 | 
						req.InitTokenConfig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 打印banner
 | 
						// 打印banner
 | 
				
			||||||
	printBanner()
 | 
						printBanner()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 初始化并赋值数据库全局变量
 | 
						// 初始化并赋值数据库全局变量
 | 
				
			||||||
	initDb()
 | 
						initDb()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 有配置redis信息,则初始化redis。多台机器部署需要使用redis存储验证码、权限、公私钥等
 | 
						// 有配置redis信息,则初始化redis。多台机器部署需要使用redis存储验证码、权限、公私钥等
 | 
				
			||||||
	initRedis()
 | 
						initRedis()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 初始化其他需要启动时运行的方法
 | 
				
			||||||
 | 
						initialize.InitOther()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 运行web服务
 | 
						// 运行web服务
 | 
				
			||||||
	runWebServer()
 | 
						runWebServer()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,9 +19,6 @@ func runWebServer() {
 | 
				
			|||||||
	// 注册路由
 | 
						// 注册路由
 | 
				
			||||||
	web := initialize.InitRouter()
 | 
						web := initialize.InitRouter()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 初始化其他需要启动时运行的方法
 | 
					 | 
				
			||||||
	initialize.InitOther()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	server := config.Conf.Server
 | 
						server := config.Conf.Server
 | 
				
			||||||
	port := server.GetPort()
 | 
						port := server.GetPort()
 | 
				
			||||||
	global.Log.Infof("Listening and serving HTTP on %s", port)
 | 
						global.Log.Infof("Listening and serving HTTP on %s", port)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,54 +0,0 @@
 | 
				
			|||||||
package utils
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"strconv"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// any类型转换为string, 如果any为nil则返回空字符串
 | 
					 | 
				
			||||||
func Any2String(val any) string {
 | 
					 | 
				
			||||||
	if value, ok := val.(string); !ok {
 | 
					 | 
				
			||||||
		return ""
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return value
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// any类型转换为int(可将字符串或int64转换), 如果any为nil则返回0
 | 
					 | 
				
			||||||
func Any2Int(val any) int {
 | 
					 | 
				
			||||||
	switch value := val.(type) {
 | 
					 | 
				
			||||||
	case int:
 | 
					 | 
				
			||||||
		return value
 | 
					 | 
				
			||||||
	case string:
 | 
					 | 
				
			||||||
		if intV, err := strconv.Atoi(value); err == nil {
 | 
					 | 
				
			||||||
			return intV
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	case int64:
 | 
					 | 
				
			||||||
		return int(value)
 | 
					 | 
				
			||||||
	case uint64:
 | 
					 | 
				
			||||||
		return int(value)
 | 
					 | 
				
			||||||
	case int32:
 | 
					 | 
				
			||||||
		return int(value)
 | 
					 | 
				
			||||||
	case uint32:
 | 
					 | 
				
			||||||
		return int(value)
 | 
					 | 
				
			||||||
	case int16:
 | 
					 | 
				
			||||||
		return int(value)
 | 
					 | 
				
			||||||
	case uint16:
 | 
					 | 
				
			||||||
		return int(value)
 | 
					 | 
				
			||||||
	case int8:
 | 
					 | 
				
			||||||
		return int(value)
 | 
					 | 
				
			||||||
	case uint8:
 | 
					 | 
				
			||||||
		return int(value)
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return 0
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// any类型转换为int64, 如果any为nil则返回0
 | 
					 | 
				
			||||||
func Any2Int64(val any) int64 {
 | 
					 | 
				
			||||||
	if value, ok := val.(int64); !ok {
 | 
					 | 
				
			||||||
		return int64(Any2Int(val))
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return value
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										77
									
								
								server/pkg/utils/anyx/anyx.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								server/pkg/utils/anyx/anyx.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
				
			|||||||
 | 
					package anyx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// any类型转换为string, 如果any为nil则返回空字符串
 | 
				
			||||||
 | 
					func ConvString(val any) string {
 | 
				
			||||||
 | 
						if value, ok := val.(string); !ok {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return value
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// any类型转换为int(可将字符串或int64转换), 如果any为nil则返回0
 | 
				
			||||||
 | 
					func ConvInt(val any) int {
 | 
				
			||||||
 | 
						switch value := val.(type) {
 | 
				
			||||||
 | 
						case int:
 | 
				
			||||||
 | 
							return value
 | 
				
			||||||
 | 
						case string:
 | 
				
			||||||
 | 
							if intV, err := strconv.Atoi(value); err == nil {
 | 
				
			||||||
 | 
								return intV
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case int64:
 | 
				
			||||||
 | 
							return int(value)
 | 
				
			||||||
 | 
						case uint64:
 | 
				
			||||||
 | 
							return int(value)
 | 
				
			||||||
 | 
						case int32:
 | 
				
			||||||
 | 
							return int(value)
 | 
				
			||||||
 | 
						case uint32:
 | 
				
			||||||
 | 
							return int(value)
 | 
				
			||||||
 | 
						case int16:
 | 
				
			||||||
 | 
							return int(value)
 | 
				
			||||||
 | 
						case uint16:
 | 
				
			||||||
 | 
							return int(value)
 | 
				
			||||||
 | 
						case int8:
 | 
				
			||||||
 | 
							return int(value)
 | 
				
			||||||
 | 
						case uint8:
 | 
				
			||||||
 | 
							return int(value)
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// any类型转换为int64, 如果any为nil则返回0
 | 
				
			||||||
 | 
					func ConvInt64(val any) int64 {
 | 
				
			||||||
 | 
						if value, ok := val.(int64); !ok {
 | 
				
			||||||
 | 
							return int64(ConvInt(val))
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return value
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func IsBlank(value any) bool {
 | 
				
			||||||
 | 
						if value == nil {
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rValue := reflect.ValueOf(value)
 | 
				
			||||||
 | 
						switch rValue.Kind() {
 | 
				
			||||||
 | 
						case reflect.String:
 | 
				
			||||||
 | 
							return rValue.Len() == 0
 | 
				
			||||||
 | 
						case reflect.Bool:
 | 
				
			||||||
 | 
							return !rValue.Bool()
 | 
				
			||||||
 | 
						case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
				
			||||||
 | 
							return rValue.Int() == 0
 | 
				
			||||||
 | 
						case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 | 
				
			||||||
 | 
							return rValue.Uint() == 0
 | 
				
			||||||
 | 
						case reflect.Float32, reflect.Float64:
 | 
				
			||||||
 | 
							return rValue.Float() == 0
 | 
				
			||||||
 | 
						case reflect.Interface, reflect.Ptr:
 | 
				
			||||||
 | 
							return rValue.IsNil()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return reflect.DeepEqual(rValue.Interface(), reflect.Zero(rValue.Type()).Interface())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,8 +1,6 @@
 | 
				
			|||||||
package utils
 | 
					package collx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import "fmt"
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 数组比较
 | 
					// 数组比较
 | 
				
			||||||
// 依次返回,新增值,删除值,以及不变值
 | 
					// 依次返回,新增值,删除值,以及不变值
 | 
				
			||||||
@@ -53,7 +51,7 @@ func NumberArr2StrArr[T NumT](numberArr []T) []string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 判断数组中是否含有指定元素
 | 
					// 判断数组中是否含有指定元素
 | 
				
			||||||
func ArrContains[T comparable](arr []T, el T) bool {
 | 
					func ArrayContains[T comparable](arr []T, el T) bool {
 | 
				
			||||||
	for _, v := range arr {
 | 
						for _, v := range arr {
 | 
				
			||||||
		if v == el {
 | 
							if v == el {
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
@@ -64,7 +62,7 @@ func ArrContains[T comparable](arr []T, el T) bool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// 数组转为map
 | 
					// 数组转为map
 | 
				
			||||||
// @param keyFunc key的主键
 | 
					// @param keyFunc key的主键
 | 
				
			||||||
func Array2Map[T any, K comparable](arr []T, keyFunc func(val T) K) map[K]T {
 | 
					func ArrayToMap[T any, K comparable](arr []T, keyFunc func(val T) K) map[K]T {
 | 
				
			||||||
	res := make(map[K]T, len(arr))
 | 
						res := make(map[K]T, len(arr))
 | 
				
			||||||
	for _, val := range arr {
 | 
						for _, val := range arr {
 | 
				
			||||||
		key := keyFunc(val)
 | 
							key := keyFunc(val)
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package utils
 | 
					package collx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package utils
 | 
					package collx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "encoding/binary"
 | 
					import "encoding/binary"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package utils
 | 
					package collx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package utils
 | 
					package collx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ConvertToINodeArray 其他的结构体想要生成菜单树,直接实现这个接口
 | 
					// ConvertToINodeArray 其他的结构体想要生成菜单树,直接实现这个接口
 | 
				
			||||||
type INode interface {
 | 
					type INode interface {
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package utils
 | 
					package cryptox
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
@@ -1,11 +1,12 @@
 | 
				
			|||||||
package utils
 | 
					package jsonx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"mayfly-go/pkg/global"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Json2Map(jsonStr string) map[string]any {
 | 
					// json字符串转map
 | 
				
			||||||
 | 
					func ToMap(jsonStr string) map[string]any {
 | 
				
			||||||
	var res map[string]any
 | 
						var res map[string]any
 | 
				
			||||||
	if jsonStr == "" {
 | 
						if jsonStr == "" {
 | 
				
			||||||
		return res
 | 
							return res
 | 
				
			||||||
@@ -14,7 +15,8 @@ func Json2Map(jsonStr string) map[string]any {
 | 
				
			|||||||
	return res
 | 
						return res
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ToJsonStr(val any) string {
 | 
					// 转换为json字符串
 | 
				
			||||||
 | 
					func ToStr(val any) string {
 | 
				
			||||||
	if strBytes, err := json.Marshal(val); err != nil {
 | 
						if strBytes, err := json.Marshal(val); err != nil {
 | 
				
			||||||
		global.Log.Error("toJsonStr error: ", err)
 | 
							global.Log.Error("toJsonStr error: ", err)
 | 
				
			||||||
		return ""
 | 
							return ""
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package utils
 | 
					package netx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/pkg/global"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package utils
 | 
					package netx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
@@ -1,9 +0,0 @@
 | 
				
			|||||||
package utils
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import "runtime"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 获取调用堆栈信息
 | 
					 | 
				
			||||||
func GetStackTrace() string {
 | 
					 | 
				
			||||||
	var buf [2 << 10]byte
 | 
					 | 
				
			||||||
	return string(buf[:runtime.Stack(buf[:], false)])
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package utils
 | 
					package stringx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"math/rand"
 | 
						"math/rand"
 | 
				
			||||||
@@ -8,7 +8,7 @@ import (
 | 
				
			|||||||
const randChar = "0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
 | 
					const randChar = "0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 生成随机字符串
 | 
					// 生成随机字符串
 | 
				
			||||||
func RandString(l int) string {
 | 
					func Rand(l int) string {
 | 
				
			||||||
	strList := []byte(randChar)
 | 
						strList := []byte(randChar)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result := []byte{}
 | 
						result := []byte{}
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package utils
 | 
					package stringx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
@@ -9,17 +9,17 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 可判断中文
 | 
					// 可判断中文
 | 
				
			||||||
func StrLen(str string) int {
 | 
					func Len(str string) int {
 | 
				
			||||||
	return len([]rune(str))
 | 
						return len([]rune(str))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 去除字符串左右空字符
 | 
					// 去除字符串左右空字符
 | 
				
			||||||
func StrTrim(str string) string {
 | 
					func Trim(str string) string {
 | 
				
			||||||
	return strings.Trim(str, " ")
 | 
						return strings.Trim(str, " ")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 去除字符串左右空字符与\n\r换行回车符
 | 
					// 去除字符串左右空字符与\n\r换行回车符
 | 
				
			||||||
func StrTrimSpaceAndBr(str string) string {
 | 
					func TrimSpaceAndBr(str string) string {
 | 
				
			||||||
	return strings.TrimFunc(str, func(r rune) bool {
 | 
						return strings.TrimFunc(str, func(r rune) bool {
 | 
				
			||||||
		s := string(r)
 | 
							s := string(r)
 | 
				
			||||||
		return s == " " || s == "\n" || s == "\r"
 | 
							return s == " " || s == "\n" || s == "\r"
 | 
				
			||||||
@@ -96,7 +96,7 @@ func TemplateResolve(temp string, data any) string {
 | 
				
			|||||||
func ReverStrTemplate(temp, str string, res map[string]any) {
 | 
					func ReverStrTemplate(temp, str string, res map[string]any) {
 | 
				
			||||||
	index := UnicodeIndex(temp, "{")
 | 
						index := UnicodeIndex(temp, "{")
 | 
				
			||||||
	ei := UnicodeIndex(temp, "}") + 1
 | 
						ei := UnicodeIndex(temp, "}") + 1
 | 
				
			||||||
	next := StrTrim(temp[ei:])
 | 
						next := Trim(temp[ei:])
 | 
				
			||||||
	nextContain := UnicodeIndex(next, "{")
 | 
						nextContain := UnicodeIndex(next, "{")
 | 
				
			||||||
	nextIndexValue := next
 | 
						nextIndexValue := next
 | 
				
			||||||
	if nextContain != -1 {
 | 
						if nextContain != -1 {
 | 
				
			||||||
@@ -106,19 +106,19 @@ func ReverStrTemplate(temp, str string, res map[string]any) {
 | 
				
			|||||||
	// 如果后面没有内容了,则取字符串的长度即可
 | 
						// 如果后面没有内容了,则取字符串的长度即可
 | 
				
			||||||
	var valueLastIndex int
 | 
						var valueLastIndex int
 | 
				
			||||||
	if nextIndexValue == "" {
 | 
						if nextIndexValue == "" {
 | 
				
			||||||
		valueLastIndex = StrLen(str)
 | 
							valueLastIndex = Len(str)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		valueLastIndex = UnicodeIndex(str, nextIndexValue)
 | 
							valueLastIndex = UnicodeIndex(str, nextIndexValue)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	value := StrTrim(SubString(str, index, valueLastIndex))
 | 
						value := Trim(SubString(str, index, valueLastIndex))
 | 
				
			||||||
	res[key] = value
 | 
						res[key] = value
 | 
				
			||||||
	// 如果后面的还有需要解析的,则递归调用解析
 | 
						// 如果后面的还有需要解析的,则递归调用解析
 | 
				
			||||||
	if nextContain != -1 {
 | 
						if nextContain != -1 {
 | 
				
			||||||
		ReverStrTemplate(next, StrTrim(SubString(str, UnicodeIndex(str, value)+StrLen(value), StrLen(str))), res)
 | 
							ReverStrTemplate(next, Trim(SubString(str, UnicodeIndex(str, value)+Len(value), Len(str))), res)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ToString(value any) string {
 | 
					func AnyToStr(value any) string {
 | 
				
			||||||
	// interface 转 string
 | 
						// interface 转 string
 | 
				
			||||||
	var key string
 | 
						var key string
 | 
				
			||||||
	if value == nil {
 | 
						if value == nil {
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package utils
 | 
					package stringx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package utils
 | 
					package structx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"database/sql"
 | 
						"database/sql"
 | 
				
			||||||
@@ -1,7 +1,8 @@
 | 
				
			|||||||
package utils
 | 
					package structx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
@@ -188,7 +189,7 @@ func TestTemplateResolve(t *testing.T) {
 | 
				
			|||||||
	d := make(map[string]string)
 | 
						d := make(map[string]string)
 | 
				
			||||||
	d["Name"] = "黄先生"
 | 
						d["Name"] = "黄先生"
 | 
				
			||||||
	d["Age"] = "23jlfdsjf"
 | 
						d["Age"] = "23jlfdsjf"
 | 
				
			||||||
	resolve := TemplateResolve("{{.Name}} is name, and {{.Age}} is age", d)
 | 
						resolve := stringx.TemplateResolve("{{.Name}} is name, and {{.Age}} is age", d)
 | 
				
			||||||
	fmt.Println(resolve)
 | 
						fmt.Println(resolve)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,7 +0,0 @@
 | 
				
			|||||||
package utils
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import "time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func DefaultTimeFormat(time time.Time) string {
 | 
					 | 
				
			||||||
	return time.Format("2006-01-02 15:04:05")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										7
									
								
								server/pkg/utils/timex/timex.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								server/pkg/utils/timex/timex.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					package timex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func DefaultFormat(time time.Time) string {
 | 
				
			||||||
 | 
						return time.Format("2006-01-02 15:04:05")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package utils
 | 
					package ymlx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
		Reference in New Issue
	
	Block a user