From 7f9e9728281e1cf00d3c7bfccfec638bf133c692 Mon Sep 17 00:00:00 2001 From: "meilin.huang" <954537473@qq.com> Date: Fri, 21 Jul 2023 17:07:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E3=80=81=E6=9C=BA=E5=99=A8=E8=AE=A1=E5=88=92=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/ops/machine/MachineList.vue | 1 - server/internal/common/api/common.go | 4 +- server/internal/db/api/db.go | 16 ++-- server/internal/db/application/db.go | 7 +- server/internal/db/application/meta.go | 4 +- server/internal/db/application/mysql_meta.go | 34 +++---- server/internal/db/application/pgsql_meta.go | 37 +++---- server/internal/machine/api/machine.go | 7 +- server/internal/machine/api/machine_script.go | 5 +- .../machine/application/machine_cronjob.go | 20 +++- .../infrastructure/machine/machine_test.go | 4 +- .../infrastructure/machine/sshtunnel.go | 4 +- .../infrastructure/persistence/machine.go | 4 +- server/internal/mongo/application/mongo.go | 7 +- server/internal/redis/api/redis.go | 7 +- server/internal/redis/api/string.go | 4 +- server/internal/redis/application/redis.go | 7 +- server/internal/sys/api/account.go | 35 ++++--- server/internal/sys/api/role.go | 6 +- server/internal/sys/application/account.go | 4 +- server/internal/sys/application/config.go | 4 +- server/internal/sys/application/resource.go | 4 +- server/internal/sys/application/syslog.go | 4 +- server/internal/tag/api/team.go | 4 +- server/mayfly-go.sql | 6 +- server/pkg/biz/assert.go | 4 +- server/pkg/config/aes.go | 6 +- server/pkg/config/config.go | 4 +- server/pkg/ginx/ginx.go | 4 +- server/pkg/gormx/query.go | 4 +- server/pkg/rediscli/lock.go | 96 +++++++++++++++++++ server/pkg/req/log_handler.go | 15 +-- server/pkg/req/permission_handler.go | 4 +- server/pkg/req/token.go | 4 +- server/pkg/starter/run.go | 9 ++ server/pkg/starter/web-server.go | 3 - server/pkg/utils/any.go | 54 ----------- server/pkg/utils/anyx/anyx.go | 77 +++++++++++++++ server/pkg/utils/{ => collx}/array.go | 10 +- server/pkg/utils/{ => collx}/array_test.go | 2 +- server/pkg/utils/{ => collx}/byte.go | 2 +- server/pkg/utils/{ => collx}/map.go | 2 +- server/pkg/utils/{ => collx}/tree.go | 2 +- .../utils/{crypto.go => cryptox/cryptox.go} | 2 +- server/pkg/utils/{json.go => jsonx/jsonx.go} | 8 +- server/pkg/utils/{net.go => netx/netx.go} | 2 +- server/pkg/utils/{ => netx}/ssh_conn_wrap.go | 2 +- server/pkg/utils/stack_trace.go | 9 -- server/pkg/utils/{ => stringx}/rand.go | 4 +- .../pkg/utils/{str.go => stringx/stringx.go} | 18 ++-- server/pkg/utils/{ => stringx}/template.go | 2 +- .../utils/{struct.go => structx/structx.go} | 2 +- .../structx_test.go} | 5 +- server/pkg/utils/time.go | 7 -- server/pkg/utils/timex/timex.go | 7 ++ server/pkg/utils/{yml.go => ymlx/ymlx.go} | 2 +- 56 files changed, 376 insertions(+), 235 deletions(-) create mode 100644 server/pkg/rediscli/lock.go delete mode 100644 server/pkg/utils/any.go create mode 100644 server/pkg/utils/anyx/anyx.go rename server/pkg/utils/{ => collx}/array.go (90%) rename server/pkg/utils/{ => collx}/array_test.go (95%) rename server/pkg/utils/{ => collx}/byte.go (97%) rename server/pkg/utils/{ => collx}/map.go (98%) rename server/pkg/utils/{ => collx}/tree.go (99%) rename server/pkg/utils/{crypto.go => cryptox/cryptox.go} (99%) rename server/pkg/utils/{json.go => jsonx/jsonx.go} (70%) rename server/pkg/utils/{net.go => netx/netx.go} (99%) rename server/pkg/utils/{ => netx}/ssh_conn_wrap.go (98%) delete mode 100644 server/pkg/utils/stack_trace.go rename server/pkg/utils/{ => stringx}/rand.go (89%) rename server/pkg/utils/{str.go => stringx/stringx.go} (89%) rename server/pkg/utils/{ => stringx}/template.go (96%) rename server/pkg/utils/{struct.go => structx/structx.go} (99%) rename server/pkg/utils/{struct_test.go => structx/structx_test.go} (97%) delete mode 100644 server/pkg/utils/time.go create mode 100644 server/pkg/utils/timex/timex.go rename server/pkg/utils/{yml.go => ymlx/ymlx.go} (97%) diff --git a/mayfly_go_web/src/views/ops/machine/MachineList.vue b/mayfly_go_web/src/views/ops/machine/MachineList.vue index c8915150..d8e809fb 100644 --- a/mayfly_go_web/src/views/ops/machine/MachineList.vue +++ b/mayfly_go_web/src/views/ops/machine/MachineList.vue @@ -251,7 +251,6 @@ onMounted(async () => { const handleCommand = (commond: any) => { const data = commond.data; const type = commond.type; - console.log(type); switch (type) { case 'detail': { showInfo(data); diff --git a/server/internal/common/api/common.go b/server/internal/common/api/common.go index d0fcd41a..febc5456 100644 --- a/server/internal/common/api/common.go +++ b/server/internal/common/api/common.go @@ -3,14 +3,14 @@ package api import ( "mayfly-go/pkg/biz" "mayfly-go/pkg/req" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/cryptox" ) type Common struct { } func (i *Common) RasPublicKey(rc *req.Ctx) { - publicKeyStr, err := utils.GetRsaPublicKey() + publicKeyStr, err := cryptox.GetRsaPublicKey() biz.ErrIsNilAppendErr(err, "rsa生成公私钥失败") rc.ResData = publicKeyStr } diff --git a/server/internal/db/api/db.go b/server/internal/db/api/db.go index 6900597b..51af841d 100644 --- a/server/internal/db/api/db.go +++ b/server/internal/db/api/db.go @@ -14,7 +14,9 @@ import ( "mayfly-go/pkg/gormx" "mayfly-go/pkg/model" "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" "strconv" "strings" @@ -57,7 +59,7 @@ func (d *Db) Save(rc *req.Ctx) { 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") db.Password = originPwd @@ -83,10 +85,10 @@ func (d *Db) GetDatabaseNames(rc *req.Ctx) { ginx.BindJsonAndValid(rc.GinCtx, form) 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") db.Password = originPwd @@ -143,7 +145,7 @@ func (d *Db) ExecSql(rc *req.Ctx) { biz.NotEmpty(form.Sql, "sql不能为空") // 去除前后空格及换行符 - sql := utils.StrTrimSpaceAndBr(form.Sql) + sql := stringx.TrimSpaceAndBr(form.Sql) execReq := &application.DbSqlExecReq{ DbId: id, @@ -158,7 +160,7 @@ func (d *Db) ExecSql(rc *req.Ctx) { isMulti := len(sqls) > 1 var execResAll *application.DbSqlExecRes for _, s := range sqls { - s = utils.StrTrimSpaceAndBr(s) + s = stringx.TrimSpaceAndBr(s) // 多条执行,如果有查询语句,则跳过 if isMulti && strings.HasPrefix(strings.ToLower(s), "select") { continue @@ -308,7 +310,7 @@ func (d *Db) DumpSql(rc *req.Ctx) { if ok { values = append(values, fmt.Sprintf("%#v", strValue)) } else { - values = append(values, utils.ToString(value)) + values = append(values, stringx.AnyToStr(value)) } } writer.WriteString(fmt.Sprintf(insertSql, table, strings.Join(values, ", "))) diff --git a/server/internal/db/application/db.go b/server/internal/db/application/db.go index 8022e016..cfd4c2c7 100644 --- a/server/internal/db/application/db.go +++ b/server/internal/db/application/db.go @@ -11,7 +11,8 @@ import ( "mayfly-go/pkg/cache" "mayfly-go/pkg/global" "mayfly-go/pkg/model" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/collx" + "mayfly-go/pkg/utils/structx" "reflect" "strconv" "strings" @@ -120,7 +121,7 @@ func (d *dbAppImpl) Save(dbEntity *entity.Db) { 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) }) for _, v := range delDb { @@ -193,7 +194,7 @@ func (da *dbAppImpl) GetDbInstance(id uint64, db string) *DbInstance { d.PwdDecrypt() dbInfo := new(DbInfo) - utils.Copy(dbInfo, d) + structx.Copy(dbInfo, d) dbInfo.Database = db dbi := &DbInstance{Id: cacheKey, Info: dbInfo} diff --git a/server/internal/db/application/meta.go b/server/internal/db/application/meta.go index 8f0a1f18..989af443 100644 --- a/server/internal/db/application/meta.go +++ b/server/internal/db/application/meta.go @@ -3,7 +3,7 @@ package application import ( "embed" "mayfly-go/pkg/biz" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/stringx" "strings" ) @@ -88,7 +88,7 @@ func GetLocalSql(file, key string) string { sqls := strings.Split(allSql, "---------------------------------------") var resSql string for _, sql := range sqls { - sql = utils.StrTrimSpaceAndBr(sql) + sql = stringx.TrimSpaceAndBr(sql) // 获取sql第一行的sql备注信息如:--MYSQL_TABLE_MA 表信息元数据 info := strings.SplitN(sql, "\n", 2) // 原始sql,即去除第一行的key与备注信息 diff --git a/server/internal/db/application/mysql_meta.go b/server/internal/db/application/mysql_meta.go index b1978ab4..cb6d7c7c 100644 --- a/server/internal/db/application/mysql_meta.go +++ b/server/internal/db/application/mysql_meta.go @@ -7,7 +7,7 @@ import ( "mayfly-go/internal/db/domain/entity" machineapp "mayfly-go/internal/machine/application" "mayfly-go/pkg/biz" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/anyx" "net" "github.com/go-sql-driver/mysql" @@ -51,7 +51,7 @@ func (mm *MysqlMetadata) GetTables() []Table { for _, re := range res { tables = append(tables, Table{ TableName: re["tableName"].(string), - TableComment: utils.Any2String(re["tableComment"]), + TableComment: anyx.ConvString(re["tableComment"]), }) } return tables @@ -74,11 +74,11 @@ func (mm *MysqlMetadata) GetColumns(tableNames ...string) []Column { columns = append(columns, Column{ TableName: re["tableName"].(string), ColumnName: re["columnName"].(string), - ColumnType: utils.Any2String(re["columnType"]), - ColumnComment: utils.Any2String(re["columnComment"]), - Nullable: utils.Any2String(re["nullable"]), - ColumnKey: utils.Any2String(re["columnKey"]), - ColumnDefault: utils.Any2String(re["columnDefault"]), + ColumnType: anyx.ConvString(re["columnType"]), + ColumnComment: anyx.ConvString(re["columnComment"]), + Nullable: anyx.ConvString(re["nullable"]), + ColumnKey: anyx.ConvString(re["columnKey"]), + ColumnDefault: anyx.ConvString(re["columnDefault"]), }) } return columns @@ -106,11 +106,11 @@ func (mm *MysqlMetadata) GetTableInfos() []Table { for _, re := range res { tables = append(tables, Table{ TableName: re["tableName"].(string), - TableComment: utils.Any2String(re["tableComment"]), - CreateTime: utils.Any2String(re["createTime"]), - TableRows: utils.Any2Int(re["tableRows"]), - DataLength: utils.Any2Int64(re["dataLength"]), - IndexLength: utils.Any2Int64(re["indexLength"]), + TableComment: anyx.ConvString(re["tableComment"]), + CreateTime: anyx.ConvString(re["createTime"]), + TableRows: anyx.ConvInt(re["tableRows"]), + DataLength: anyx.ConvInt64(re["dataLength"]), + IndexLength: anyx.ConvInt64(re["indexLength"]), }) } return tables @@ -124,11 +124,11 @@ func (mm *MysqlMetadata) GetTableIndex(tableName string) []Index { for _, re := range res { indexs = append(indexs, Index{ IndexName: re["indexName"].(string), - ColumnName: utils.Any2String(re["columnName"]), - IndexType: utils.Any2String(re["indexType"]), - IndexComment: utils.Any2String(re["indexComment"]), - NonUnique: utils.Any2Int(re["nonUnique"]), - SeqInIndex: utils.Any2Int(re["seqInIndex"]), + ColumnName: anyx.ConvString(re["columnName"]), + IndexType: anyx.ConvString(re["indexType"]), + IndexComment: anyx.ConvString(re["indexComment"]), + NonUnique: anyx.ConvInt(re["nonUnique"]), + SeqInIndex: anyx.ConvInt(re["seqInIndex"]), }) } // 把查询结果以索引名分组,索引字段以逗号连接 diff --git a/server/internal/db/application/pgsql_meta.go b/server/internal/db/application/pgsql_meta.go index d6ac4b84..b826cd8d 100644 --- a/server/internal/db/application/pgsql_meta.go +++ b/server/internal/db/application/pgsql_meta.go @@ -7,7 +7,8 @@ import ( "mayfly-go/internal/db/domain/entity" machineapp "mayfly-go/internal/machine/application" "mayfly-go/pkg/biz" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/anyx" + "mayfly-go/pkg/utils/collx" "net" "strings" "time" @@ -21,7 +22,7 @@ func getPgsqlDB(d *entity.Db, db string) (*sql.DB, error) { if d.SshTunnelMachineId > 0 { // 如果使用了隧道,则使用`postgres:ssh:隧道机器id`注册名 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.Drivers() @@ -78,7 +79,7 @@ func (pm *PgsqlMetadata) GetTables() []Table { for _, re := range res { tables = append(tables, Table{ TableName: re["tableName"].(string), - TableComment: utils.Any2String(re["tableComment"]), + TableComment: anyx.ConvString(re["tableComment"]), }) } return tables @@ -101,11 +102,11 @@ func (pm *PgsqlMetadata) GetColumns(tableNames ...string) []Column { columns = append(columns, Column{ TableName: re["tableName"].(string), ColumnName: re["columnName"].(string), - ColumnType: utils.Any2String(re["columnType"]), - ColumnComment: utils.Any2String(re["columnComment"]), - Nullable: utils.Any2String(re["nullable"]), - ColumnKey: utils.Any2String(re["columnKey"]), - ColumnDefault: utils.Any2String(re["columnDefault"]), + ColumnType: anyx.ConvString(re["columnType"]), + ColumnComment: anyx.ConvString(re["columnComment"]), + Nullable: anyx.ConvString(re["nullable"]), + ColumnKey: anyx.ConvString(re["columnKey"]), + ColumnDefault: anyx.ConvString(re["columnDefault"]), }) } return columns @@ -132,11 +133,11 @@ func (pm *PgsqlMetadata) GetTableInfos() []Table { for _, re := range res { tables = append(tables, Table{ TableName: re["tableName"].(string), - TableComment: utils.Any2String(re["tableComment"]), - CreateTime: utils.Any2String(re["createTime"]), - TableRows: utils.Any2Int(re["tableRows"]), - DataLength: utils.Any2Int64(re["dataLength"]), - IndexLength: utils.Any2Int64(re["indexLength"]), + TableComment: anyx.ConvString(re["tableComment"]), + CreateTime: anyx.ConvString(re["createTime"]), + TableRows: anyx.ConvInt(re["tableRows"]), + DataLength: anyx.ConvInt64(re["dataLength"]), + IndexLength: anyx.ConvInt64(re["indexLength"]), }) } return tables @@ -150,11 +151,11 @@ func (pm *PgsqlMetadata) GetTableIndex(tableName string) []Index { for _, re := range res { indexs = append(indexs, Index{ IndexName: re["indexName"].(string), - ColumnName: utils.Any2String(re["columnName"]), - IndexType: utils.Any2String(re["indexType"]), - IndexComment: utils.Any2String(re["indexComment"]), - NonUnique: utils.Any2Int(re["nonUnique"]), - SeqInIndex: utils.Any2Int(re["seqInIndex"]), + ColumnName: anyx.ConvString(re["columnName"]), + IndexType: anyx.ConvString(re["indexType"]), + IndexComment: anyx.ConvString(re["indexComment"]), + NonUnique: anyx.ConvInt(re["nonUnique"]), + SeqInIndex: anyx.ConvInt(re["seqInIndex"]), }) } return indexs diff --git a/server/internal/machine/api/machine.go b/server/internal/machine/api/machine.go index bc69aa31..0ea3d754 100644 --- a/server/internal/machine/api/machine.go +++ b/server/internal/machine/api/machine.go @@ -14,7 +14,8 @@ import ( "mayfly-go/pkg/ginx" "mayfly-go/pkg/model" "mayfly-go/pkg/req" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/stringx" + "mayfly-go/pkg/utils/structx" "mayfly-go/pkg/ws" "os" "path" @@ -82,7 +83,7 @@ func (m *Machine) TestConn(rc *req.Ctx) { ginx.BindJsonAndValid(g, machineForm) me := new(entity.Machine) - utils.Copy(me, machineForm) + structx.Copy(me, machineForm) m.MachineApp.TestConn(me) } @@ -192,7 +193,7 @@ func (m *Machine) WsSSH(g *gin.Context) { 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") // 记录系统操作日志 diff --git a/server/internal/machine/api/machine_script.go b/server/internal/machine/api/machine_script.go index e43092ce..51cef5b5 100644 --- a/server/internal/machine/api/machine_script.go +++ b/server/internal/machine/api/machine_script.go @@ -10,7 +10,8 @@ import ( "mayfly-go/pkg/biz" "mayfly-go/pkg/ginx" "mayfly-go/pkg/req" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/jsonx" + "mayfly-go/pkg/utils/stringx" "strconv" "strings" @@ -63,7 +64,7 @@ func (m *MachineScript) RunMachineScript(rc *req.Ctx) { script := ms.Script // 如果有脚本参数,则用脚本参数替换脚本中的模板占位符参数 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) biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().TagPath), "%s") diff --git a/server/internal/machine/application/machine_cronjob.go b/server/internal/machine/application/machine_cronjob.go index 51b9722f..3bddf590 100644 --- a/server/internal/machine/application/machine_cronjob.go +++ b/server/internal/machine/application/machine_cronjob.go @@ -5,8 +5,10 @@ import ( "mayfly-go/internal/machine/domain/repository" "mayfly-go/pkg/global" "mayfly-go/pkg/model" + "mayfly-go/pkg/rediscli" "mayfly-go/pkg/scheduler" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/collx" + "mayfly-go/pkg/utils/stringx" "time" ) @@ -107,7 +109,7 @@ func (m *machineCropJobAppImpl) GetRelateCronJobIds(machineId uint64) []uint64 { func (m *machineCropJobAppImpl) CronJobRelateMachines(cronJobId uint64, machineIds []uint64, la *model.LoginAccount) { 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) 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) { 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) now := time.Now() @@ -186,7 +188,7 @@ func (m *machineCropJobAppImpl) addCronJob(mcj *entity.MachineCronJob) { var key string isDisable := mcj.Status == entity.MachineCronJobStatusDisable if mcj.Id == 0 { - key = utils.RandString(16) + key = stringx.Rand(16) mcj.Key = key if isDisable { return @@ -201,11 +203,19 @@ func (m *machineCropJobAppImpl) addCronJob(mcj *entity.MachineCronJob) { } scheduler.AddFunByKey(key, mcj.Cron, func() { - m.runCronJob(key) + go m.runCronJob(key) }) } 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.Key = key err := m.machineCropJobRepo.GetBy(cronJob) diff --git a/server/internal/machine/infrastructure/machine/machine_test.go b/server/internal/machine/infrastructure/machine/machine_test.go index d0575f3f..00018803 100644 --- a/server/internal/machine/infrastructure/machine/machine_test.go +++ b/server/internal/machine/infrastructure/machine/machine_test.go @@ -2,7 +2,7 @@ package machine import ( "fmt" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/stringx" "strings" "testing" ) @@ -69,7 +69,7 @@ func TestTemplateRev(t *testing.T) { //key := temp[index+1 : ei-1] //value := SubString(str, index, UnicodeIndex(str, next)) res := make(map[string]any) - utils.ReverStrTemplate(temp, str, res) + stringx.ReverStrTemplate(temp, str, res) fmt.Println(res) } diff --git a/server/internal/machine/infrastructure/machine/sshtunnel.go b/server/internal/machine/infrastructure/machine/sshtunnel.go index 853df102..17a9cacc 100644 --- a/server/internal/machine/infrastructure/machine/sshtunnel.go +++ b/server/internal/machine/infrastructure/machine/sshtunnel.go @@ -5,7 +5,7 @@ import ( "io" "mayfly-go/pkg/global" "mayfly-go/pkg/scheduler" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/netx" "net" "os" "sync" @@ -75,7 +75,7 @@ func (stm *SshTunnelMachine) OpenSshTunnel(id uint64, ip string, port int) (expo stm.mutex.Lock() defer stm.mutex.Unlock() - localPort, err := utils.GetAvailablePort() + localPort, err := netx.GetAvailablePort() if err != nil { return "", 0, err } diff --git a/server/internal/machine/infrastructure/persistence/machine.go b/server/internal/machine/infrastructure/persistence/machine.go index e0c4a9a1..07e9b34a 100644 --- a/server/internal/machine/infrastructure/persistence/machine.go +++ b/server/internal/machine/infrastructure/persistence/machine.go @@ -7,7 +7,7 @@ import ( "mayfly-go/pkg/biz" "mayfly-go/pkg/gormx" "mayfly-go/pkg/model" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/collx" "strconv" "strings" ) @@ -29,7 +29,7 @@ func (m *machineRepoImpl) GetMachineList(condition *entity.MachineQuery, pagePar if condition.Ids != "" { // ,分割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) return uint64(id) })) diff --git a/server/internal/mongo/application/mongo.go b/server/internal/mongo/application/mongo.go index 04da95c6..a2e4e104 100644 --- a/server/internal/mongo/application/mongo.go +++ b/server/internal/mongo/application/mongo.go @@ -12,7 +12,8 @@ import ( "mayfly-go/pkg/cache" "mayfly-go/pkg/global" "mayfly-go/pkg/model" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/netx" + "mayfly-go/pkg/utils/structx" "net" "regexp" "time" @@ -201,7 +202,7 @@ func connect(me *entity.Mongo) (*MongoInstance, error) { func toMongiInfo(me *entity.Mongo) *MongoInfo { mi := new(MongoInfo) - utils.Copy(mi, me) + structx.Copy(mi, me) return mi } @@ -212,7 +213,7 @@ type MongoSshDialer struct { 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 { // 将ssh conn包装,否则内部部设置超时会报错,ssh conn不支持设置超时会返回错误: ssh: tcpChan: deadline not supported - return &utils.WrapSshConn{Conn: sshConn}, nil + return &netx.WrapSshConn{Conn: sshConn}, nil } else { return nil, err } diff --git a/server/internal/redis/api/redis.go b/server/internal/redis/api/redis.go index 0f5464bc..d524d6e4 100644 --- a/server/internal/redis/api/redis.go +++ b/server/internal/redis/api/redis.go @@ -11,7 +11,8 @@ import ( "mayfly-go/pkg/ginx" "mayfly-go/pkg/model" "mayfly-go/pkg/req" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/cryptox" + "mayfly-go/pkg/utils/stringx" "strconv" "strings" @@ -47,7 +48,7 @@ func (r *Redis) Save(rc *req.Ctx) { 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") redis.Password = originPwd @@ -133,7 +134,7 @@ func (r *Redis) RedisInfo(rc *req.Ctx) { break } 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++ key = strings.Trim(key, " ") diff --git a/server/internal/redis/api/string.go b/server/internal/redis/api/string.go index 408f7a73..8751781e 100644 --- a/server/internal/redis/api/string.go +++ b/server/internal/redis/api/string.go @@ -7,7 +7,7 @@ import ( "mayfly-go/pkg/biz" "mayfly-go/pkg/ginx" "mayfly-go/pkg/req" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/stringx" "time" ) @@ -25,7 +25,7 @@ func (r *Redis) SetStringValue(rc *req.Ctx) { ri := r.getRedisIns(rc) 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() biz.ErrIsNilAppendErr(err, "保存字符串值失败: %s") diff --git a/server/internal/redis/application/redis.go b/server/internal/redis/application/redis.go index c77098ee..52991ff3 100644 --- a/server/internal/redis/application/redis.go +++ b/server/internal/redis/application/redis.go @@ -12,7 +12,8 @@ import ( "mayfly-go/pkg/cache" "mayfly-go/pkg/global" "mayfly-go/pkg/model" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/netx" + "mayfly-go/pkg/utils/structx" "net" "strconv" "strings" @@ -176,7 +177,7 @@ func getRedisCacheKey(id uint64, db int) string { func toRedisInfo(re *entity.Redis, db int) *RedisInfo { redisInfo := new(RedisInfo) - utils.Copy(redisInfo, re) + structx.Copy(redisInfo, re) redisInfo.Db = db 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) { if sshConn, err := sshTunnel.GetDialConn(network, addr); err == nil { // 将ssh conn包装,否则redis内部设置超时会报错,ssh conn不支持设置超时会返回错误: ssh: tcpChan: deadline not supported - return &utils.WrapSshConn{Conn: sshConn}, nil + return &netx.WrapSshConn{Conn: sshConn}, nil } else { return nil, err } diff --git a/server/internal/sys/api/account.go b/server/internal/sys/api/account.go index 426f39fe..2667d95a 100644 --- a/server/internal/sys/api/account.go +++ b/server/internal/sys/api/account.go @@ -16,7 +16,12 @@ import ( "mayfly-go/pkg/model" "mayfly-go/pkg/otp" "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" "strconv" "strings" @@ -55,7 +60,7 @@ func (a *Account) Login(rc *req.Ctx) { clientIp := getIpAndRegion(rc) 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") account := &entity.Account{Username: username} @@ -67,7 +72,7 @@ func (a *Account) Login(rc *req.Ctx) { loginFailMin := accountLoginSecurity.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++ cache.SetStr(failCountKey, strconv.Itoa(nowFailCount), time.Minute*time.Duration(loginFailMin)) panic(biz.NewBizErr(fmt.Sprintf("用户名或密码错误【当前登录失败%d次】", nowFailCount))) @@ -96,7 +101,7 @@ func (a *Account) Login(rc *req.Ctx) { // 修改状态为已注册 otpStatus = OtpStatusReg // 该token用于otp双因素校验 - token = utils.RandString(32) + token = stringx.Rand(32) // 未注册otp secret或重置了秘钥 if otpSecret == "" || otpSecret == "-" { otpStatus = OtpStatusNoReg @@ -116,7 +121,7 @@ func (a *Account) Login(rc *req.Ctx) { OtpSecret: otpSecret, 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 { // 不进行otp二次校验则直接返回accessToken token = accessToken @@ -133,7 +138,7 @@ func (a *Account) Login(rc *req.Ctx) { // 获取ip与归属地信息 func getIpAndRegion(rc *req.Ctx) string { 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 { @@ -214,22 +219,22 @@ func (a *Account) ChangePassword(rc *req.Ctx) { form := new(form.AccountChangePasswordForm) ginx.BindJsonAndValid(rc.GinCtx, form) - originOldPwd, err := utils.DefaultRsaDecrypt(form.OldPassword, true) + originOldPwd, err := cryptox.DefaultRsaDecrypt(form.OldPassword, true) biz.ErrIsNilAppendErr(err, "解密旧密码错误: %s") account := &entity.Account{Username: form.Username} err = a.AccountApp.GetAccount(account, "Id", "Username", "Password", "Status") biz.ErrIsNil(err, "旧密码错误") - biz.IsTrue(utils.CheckPwdHash(originOldPwd, account.Password), "旧密码错误") + biz.IsTrue(cryptox.CheckPwdHash(originOldPwd, account.Password), "旧密码错误") biz.IsTrue(account.IsEnable(), "该账号不可用") - originNewPwd, err := utils.DefaultRsaDecrypt(form.NewPassword, true) + originNewPwd, err := cryptox.DefaultRsaDecrypt(form.NewPassword, true) biz.ErrIsNilAppendErr(err, "解密新密码错误: %s") biz.IsTrue(CheckPasswordLever(originNewPwd), "密码强度必须8位以上且包含字⺟⼤⼩写+数字+特殊符号") updateAccount := new(entity.Account) updateAccount.Id = account.Id - updateAccount.Password = utils.PwdHash(originNewPwd) + updateAccount.Password = cryptox.PwdHash(originNewPwd) a.AccountApp.Update(updateAccount) // 赋值loginAccount 主要用于记录操作日志,因为操作日志保存请求上下文没有该信息不保存日志 @@ -267,7 +272,7 @@ func (a *Account) saveLogin(account *entity.Account, ip string) { // 创建登录消息 loginMsg := &msgentity.Msg{ RecipientId: int64(account.Id), - Msg: fmt.Sprintf("于[%s]-[%s]登录", ip, utils.DefaultTimeFormat(now)), + Msg: fmt.Sprintf("于[%s]-[%s]登录", ip, timex.DefaultFormat(now)), Type: 1, } loginMsg.CreateTime = &now @@ -295,7 +300,7 @@ func (a *Account) UpdateAccount(rc *req.Ctx) { if updateAccount.Password != "" { biz.IsTrue(CheckPasswordLever(updateAccount.Password), "密码强度必须8位以上且包含字⺟⼤⼩写+数字+特殊符号") - updateAccount.Password = utils.PwdHash(updateAccount.Password) + updateAccount.Password = cryptox.PwdHash(updateAccount.Password) } a.AccountApp.Update(updateAccount) } @@ -323,7 +328,7 @@ func (a *Account) SaveAccount(rc *req.Ctx) { } else { if account.Password != "" { biz.IsTrue(CheckPasswordLever(account.Password), "密码强度必须8位以上且包含字⺟⼤⼩写+数字+特殊符号") - account.Password = utils.PwdHash(account.Password) + account.Password = cryptox.PwdHash(account.Password) } a.AccountApp.Update(account) } @@ -380,14 +385,14 @@ func (a *Account) SaveRoles(rc *req.Ctx) { 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) return uint64(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 }) diff --git a/server/internal/sys/api/role.go b/server/internal/sys/api/role.go index ba1b8a6b..fcc85c83 100644 --- a/server/internal/sys/api/role.go +++ b/server/internal/sys/api/role.go @@ -9,7 +9,7 @@ import ( "mayfly-go/pkg/ginx" "mayfly-go/pkg/model" "mayfly-go/pkg/req" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/collx" "strconv" "strings" "time" @@ -72,14 +72,14 @@ func (r *Role) SaveResource(rc *req.Ctx) { 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) return uint64(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 }) diff --git a/server/internal/sys/application/account.go b/server/internal/sys/application/account.go index c54517f6..fefc432b 100644 --- a/server/internal/sys/application/account.go +++ b/server/internal/sys/application/account.go @@ -6,7 +6,7 @@ import ( "mayfly-go/pkg/biz" "mayfly-go/pkg/gormx" "mayfly-go/pkg/model" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/cryptox" "gorm.io/gorm" ) @@ -45,7 +45,7 @@ func (a *accountAppImpl) GetPageList(condition *entity.Account, pageParam *model func (a *accountAppImpl) Create(account *entity.Account) { 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 a.accountRepo.Insert(account) } diff --git a/server/internal/sys/application/config.go b/server/internal/sys/application/config.go index afda7a52..75cbe6d8 100644 --- a/server/internal/sys/application/config.go +++ b/server/internal/sys/application/config.go @@ -7,7 +7,7 @@ import ( "mayfly-go/pkg/cache" "mayfly-go/pkg/global" "mayfly-go/pkg/model" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/jsonx" ) 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 { global.Log.Warnf("不存在key = [%s] 的系统配置", key) } else { - cache.SetStr(SysConfigKeyPrefix+key, utils.ToJsonStr(config), -1) + cache.SetStr(SysConfigKeyPrefix+key, jsonx.ToStr(config), -1) } return config } diff --git a/server/internal/sys/application/resource.go b/server/internal/sys/application/resource.go index 5a04a8e4..38983ae6 100644 --- a/server/internal/sys/application/resource.go +++ b/server/internal/sys/application/resource.go @@ -5,7 +5,7 @@ import ( "mayfly-go/internal/sys/domain/repository" "mayfly-go/pkg/biz" "mayfly-go/pkg/gormx" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/stringx" "strings" "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 { pResource := r.GetById(uint64(pid)) biz.IsTrue(pResource != nil, "该父资源不存在") diff --git a/server/internal/sys/application/syslog.go b/server/internal/sys/application/syslog.go index 4913c939..381c8b8d 100644 --- a/server/internal/sys/application/syslog.go +++ b/server/internal/sys/application/syslog.go @@ -8,7 +8,7 @@ import ( "mayfly-go/pkg/biz" "mayfly-go/pkg/model" "mayfly-go/pkg/req" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/anyx" "time" ) @@ -50,7 +50,7 @@ func (m *syslogAppImpl) SaveFromReq(req *req.Ctx) { } reqParam := req.ReqParam - if !utils.IsBlank(reqParam) { + if !anyx.IsBlank(reqParam) { // 如果是字符串类型,则不使用json序列化 if reqStr, ok := reqParam.(string); ok { syslog.ReqParam = reqStr diff --git a/server/internal/tag/api/team.go b/server/internal/tag/api/team.go index af3d8a62..1c79a0b9 100644 --- a/server/internal/tag/api/team.go +++ b/server/internal/tag/api/team.go @@ -11,7 +11,7 @@ import ( "mayfly-go/pkg/biz" "mayfly-go/pkg/ginx" "mayfly-go/pkg/req" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/collx" "strconv" "strings" ) @@ -125,7 +125,7 @@ func (p *Team) SaveTags(rc *req.Ctx) { 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 }) diff --git a/server/mayfly-go.sql b/server/mayfly-go.sql index 3061c88d..ec131146 100644 --- a/server/mayfly-go.sql +++ b/server/mayfly-go.sql @@ -253,7 +253,7 @@ CREATE TABLE `t_machine_cron_job` ( `modifier` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL, `create_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, PRIMARY KEY (`id`) ) 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 '状态', `res` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin 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, PRIMARY KEY (`id`) ) 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` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin 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, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='机器计划任务关联表'; diff --git a/server/pkg/biz/assert.go b/server/pkg/biz/assert.go index cf6c42e4..29472ccf 100644 --- a/server/pkg/biz/assert.go +++ b/server/pkg/biz/assert.go @@ -3,7 +3,7 @@ package biz import ( "fmt" "mayfly-go/pkg/global" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/anyx" "reflect" ) @@ -56,7 +56,7 @@ func NotNil(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...))) } } diff --git a/server/pkg/config/aes.go b/server/pkg/config/aes.go index 61d28704..ba8b9694 100644 --- a/server/pkg/config/aes.go +++ b/server/pkg/config/aes.go @@ -2,8 +2,8 @@ package config import ( "fmt" - "mayfly-go/pkg/utils" "mayfly-go/pkg/utils/assert" + "mayfly-go/pkg/utils/cryptox" ) type Aes struct { @@ -12,12 +12,12 @@ type Aes struct { // 编码并base64 func (a *Aes) EncryptBase64(data []byte) (string, error) { - return utils.AesEncryptBase64(data, []byte(a.Key)) + return cryptox.AesEncryptBase64(data, []byte(a.Key)) } // base64解码后再aes解码 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() { diff --git a/server/pkg/config/config.go b/server/pkg/config/config.go index 12948c24..99dc2427 100644 --- a/server/pkg/config/config.go +++ b/server/pkg/config/config.go @@ -3,8 +3,8 @@ package config import ( "flag" "fmt" - "mayfly-go/pkg/utils" "mayfly-go/pkg/utils/assert" + "mayfly-go/pkg/utils/ymlx" "os" "path/filepath" ) @@ -20,7 +20,7 @@ func Init() { startConfigParam := &CmdConfigParam{ConfigFilePath: path} // 读取配置文件信息 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())) } // 校验配置文件内容信息 diff --git a/server/pkg/ginx/ginx.go b/server/pkg/ginx/ginx.go index 8ccb67f8..b3997782 100644 --- a/server/pkg/ginx/ginx.go +++ b/server/pkg/ginx/ginx.go @@ -5,7 +5,7 @@ import ( "mayfly-go/pkg/biz" "mayfly-go/pkg/global" "mayfly-go/pkg/model" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/structx" "net/http" "runtime/debug" "strconv" @@ -25,7 +25,7 @@ func BindJsonAndValid[T any](g *gin.Context, data T) T { // 绑定请求体中的json至form结构体,并拷贝至另一结构体 func BindJsonAndCopyTo[T any](g *gin.Context, form any, toStruct T) T { BindJsonAndValid(g, form) - utils.Copy(toStruct, form) + structx.Copy(toStruct, form) return toStruct } diff --git a/server/pkg/gormx/query.go b/server/pkg/gormx/query.go index 6e43f794..905c1234 100644 --- a/server/pkg/gormx/query.go +++ b/server/pkg/gormx/query.go @@ -5,7 +5,7 @@ import ( "mayfly-go/pkg/consts" "mayfly-go/pkg/global" "mayfly-go/pkg/model" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/anyx" "strings" "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 { // 零值跳过 - if skipBlank && utils.IsBlank(val) { + if skipBlank && anyx.IsBlank(val) { return q } q.columns = append(q.columns, fmt.Sprintf("%s %s ?", column, cond)) diff --git a/server/pkg/rediscli/lock.go b/server/pkg/rediscli/lock.go new file mode 100644 index 00000000..604692ac --- /dev/null +++ b/server/pkg/rediscli/lock.go @@ -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 +} diff --git a/server/pkg/req/log_handler.go b/server/pkg/req/log_handler.go index bc78f6a3..533e67ce 100644 --- a/server/pkg/req/log_handler.go +++ b/server/pkg/req/log_handler.go @@ -4,7 +4,8 @@ import ( "fmt" "mayfly-go/pkg/biz" "mayfly-go/pkg/logger" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/anyx" + "mayfly-go/pkg/utils/stringx" "github.com/sirupsen/logrus" ) @@ -72,21 +73,21 @@ func LogHandler(rc *Ctx) error { func getLogMsg(rc *Ctx) string { logInfo := rc.Conf.logInfo msg := logInfo.Description + fmt.Sprintf(" ->%dms", rc.timed) - if !utils.IsBlank(rc.ReqParam) { - msg = msg + fmt.Sprintf("\n--> %s", utils.ToString(rc.ReqParam)) + if !anyx.IsBlank(rc.ReqParam) { + msg = msg + fmt.Sprintf("\n--> %s", stringx.AnyToStr(rc.ReqParam)) } // 返回结果不为空,则记录返回结果 - if logInfo.LogResp && !utils.IsBlank(rc.ResData) { - msg = msg + fmt.Sprintf("\n<-- %s", utils.ToString(rc.ResData)) + if logInfo.LogResp && !anyx.IsBlank(rc.ResData) { + msg = msg + fmt.Sprintf("\n<-- %s", stringx.AnyToStr(rc.ResData)) } return msg } func getErrMsg(rc *Ctx, err any) string { msg := rc.Conf.logInfo.Description - if !utils.IsBlank(rc.ReqParam) { - msg = msg + fmt.Sprintf("\n--> %s", utils.ToString(rc.ReqParam)) + if !anyx.IsBlank(rc.ReqParam) { + msg = msg + fmt.Sprintf("\n--> %s", stringx.AnyToStr(rc.ReqParam)) } var errMsg string diff --git a/server/pkg/req/permission_handler.go b/server/pkg/req/permission_handler.go index 7e30bbc1..42dba034 100644 --- a/server/pkg/req/permission_handler.go +++ b/server/pkg/req/permission_handler.go @@ -7,7 +7,7 @@ import ( "mayfly-go/pkg/cache" "mayfly-go/pkg/config" "mayfly-go/pkg/rediscli" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/stringx" "time" ) @@ -124,7 +124,7 @@ type RedisPermissionCodeRegistry struct { } 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 { diff --git a/server/pkg/req/token.go b/server/pkg/req/token.go index c6b120a4..86b0c687 100644 --- a/server/pkg/req/token.go +++ b/server/pkg/req/token.go @@ -7,7 +7,7 @@ import ( "mayfly-go/pkg/config" "mayfly-go/pkg/global" "mayfly-go/pkg/model" - "mayfly-go/pkg/utils" + "mayfly-go/pkg/utils/stringx" "time" "github.com/golang-jwt/jwt/v5" @@ -35,7 +35,7 @@ func CreateToken(userId uint64, username string) string { // 如果配置文件中的jwt key为空,则随机生成字符串 if JwtKey == "" { - JwtKey = utils.RandString(32) + JwtKey = stringx.Rand(32) global.Log.Infof("config.yml未配置jwt.key, 随机生成key为: %s", JwtKey) } // 使用自定义字符串加密 and get the complete encoded token as a string diff --git a/server/pkg/starter/run.go b/server/pkg/starter/run.go index 9d26f16b..15e80789 100644 --- a/server/pkg/starter/run.go +++ b/server/pkg/starter/run.go @@ -1,6 +1,7 @@ package starter import ( + "mayfly-go/initialize" "mayfly-go/pkg/config" "mayfly-go/pkg/logger" "mayfly-go/pkg/req" @@ -9,17 +10,25 @@ import ( func RunWebServer() { // 初始化config.yml配置文件映射信息 config.Init() + // 初始化日志配置信息 logger.Init() + // 初始化jwt key与expire time等 req.InitTokenConfig() // 打印banner printBanner() + // 初始化并赋值数据库全局变量 initDb() + // 有配置redis信息,则初始化redis。多台机器部署需要使用redis存储验证码、权限、公私钥等 initRedis() + + // 初始化其他需要启动时运行的方法 + initialize.InitOther() + // 运行web服务 runWebServer() } diff --git a/server/pkg/starter/web-server.go b/server/pkg/starter/web-server.go index 3c7d51bc..bc6cac19 100644 --- a/server/pkg/starter/web-server.go +++ b/server/pkg/starter/web-server.go @@ -19,9 +19,6 @@ func runWebServer() { // 注册路由 web := initialize.InitRouter() - // 初始化其他需要启动时运行的方法 - initialize.InitOther() - server := config.Conf.Server port := server.GetPort() global.Log.Infof("Listening and serving HTTP on %s", port) diff --git a/server/pkg/utils/any.go b/server/pkg/utils/any.go deleted file mode 100644 index 2f9b8dac..00000000 --- a/server/pkg/utils/any.go +++ /dev/null @@ -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 - } -} diff --git a/server/pkg/utils/anyx/anyx.go b/server/pkg/utils/anyx/anyx.go new file mode 100644 index 00000000..a5527b35 --- /dev/null +++ b/server/pkg/utils/anyx/anyx.go @@ -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()) +} diff --git a/server/pkg/utils/array.go b/server/pkg/utils/collx/array.go similarity index 90% rename from server/pkg/utils/array.go rename to server/pkg/utils/collx/array.go index 0f9bee9d..bbc06635 100644 --- a/server/pkg/utils/array.go +++ b/server/pkg/utils/collx/array.go @@ -1,8 +1,6 @@ -package utils +package collx -import ( - "fmt" -) +import "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 { if v == el { return true @@ -64,7 +62,7 @@ func ArrContains[T comparable](arr []T, el T) bool { // 数组转为map // @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)) for _, val := range arr { key := keyFunc(val) diff --git a/server/pkg/utils/array_test.go b/server/pkg/utils/collx/array_test.go similarity index 95% rename from server/pkg/utils/array_test.go rename to server/pkg/utils/collx/array_test.go index 504153f7..4fa78db8 100644 --- a/server/pkg/utils/array_test.go +++ b/server/pkg/utils/collx/array_test.go @@ -1,4 +1,4 @@ -package utils +package collx import ( "fmt" diff --git a/server/pkg/utils/byte.go b/server/pkg/utils/collx/byte.go similarity index 97% rename from server/pkg/utils/byte.go rename to server/pkg/utils/collx/byte.go index ff36bf18..22c2dff3 100644 --- a/server/pkg/utils/byte.go +++ b/server/pkg/utils/collx/byte.go @@ -1,4 +1,4 @@ -package utils +package collx import "encoding/binary" diff --git a/server/pkg/utils/map.go b/server/pkg/utils/collx/map.go similarity index 98% rename from server/pkg/utils/map.go rename to server/pkg/utils/collx/map.go index 19f8311e..0d5e8115 100644 --- a/server/pkg/utils/map.go +++ b/server/pkg/utils/collx/map.go @@ -1,4 +1,4 @@ -package utils +package collx import ( "reflect" diff --git a/server/pkg/utils/tree.go b/server/pkg/utils/collx/tree.go similarity index 99% rename from server/pkg/utils/tree.go rename to server/pkg/utils/collx/tree.go index f14ae366..45cd63a5 100644 --- a/server/pkg/utils/tree.go +++ b/server/pkg/utils/collx/tree.go @@ -1,4 +1,4 @@ -package utils +package collx // ConvertToINodeArray 其他的结构体想要生成菜单树,直接实现这个接口 type INode interface { diff --git a/server/pkg/utils/crypto.go b/server/pkg/utils/cryptox/cryptox.go similarity index 99% rename from server/pkg/utils/crypto.go rename to server/pkg/utils/cryptox/cryptox.go index 2ac34bb1..401059c6 100644 --- a/server/pkg/utils/crypto.go +++ b/server/pkg/utils/cryptox/cryptox.go @@ -1,4 +1,4 @@ -package utils +package cryptox import ( "bytes" diff --git a/server/pkg/utils/json.go b/server/pkg/utils/jsonx/jsonx.go similarity index 70% rename from server/pkg/utils/json.go rename to server/pkg/utils/jsonx/jsonx.go index bbd9b07b..cc7b08ac 100644 --- a/server/pkg/utils/json.go +++ b/server/pkg/utils/jsonx/jsonx.go @@ -1,11 +1,12 @@ -package utils +package jsonx import ( "encoding/json" "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 if jsonStr == "" { return res @@ -14,7 +15,8 @@ func Json2Map(jsonStr string) map[string]any { return res } -func ToJsonStr(val any) string { +// 转换为json字符串 +func ToStr(val any) string { if strBytes, err := json.Marshal(val); err != nil { global.Log.Error("toJsonStr error: ", err) return "" diff --git a/server/pkg/utils/net.go b/server/pkg/utils/netx/netx.go similarity index 99% rename from server/pkg/utils/net.go rename to server/pkg/utils/netx/netx.go index 72f0fee1..899140e3 100644 --- a/server/pkg/utils/net.go +++ b/server/pkg/utils/netx/netx.go @@ -1,4 +1,4 @@ -package utils +package netx import ( "mayfly-go/pkg/global" diff --git a/server/pkg/utils/ssh_conn_wrap.go b/server/pkg/utils/netx/ssh_conn_wrap.go similarity index 98% rename from server/pkg/utils/ssh_conn_wrap.go rename to server/pkg/utils/netx/ssh_conn_wrap.go index 1135fcfe..9ec1201c 100644 --- a/server/pkg/utils/ssh_conn_wrap.go +++ b/server/pkg/utils/netx/ssh_conn_wrap.go @@ -1,4 +1,4 @@ -package utils +package netx import ( "net" diff --git a/server/pkg/utils/stack_trace.go b/server/pkg/utils/stack_trace.go deleted file mode 100644 index 52b681dd..00000000 --- a/server/pkg/utils/stack_trace.go +++ /dev/null @@ -1,9 +0,0 @@ -package utils - -import "runtime" - -// 获取调用堆栈信息 -func GetStackTrace() string { - var buf [2 << 10]byte - return string(buf[:runtime.Stack(buf[:], false)]) -} diff --git a/server/pkg/utils/rand.go b/server/pkg/utils/stringx/rand.go similarity index 89% rename from server/pkg/utils/rand.go rename to server/pkg/utils/stringx/rand.go index 2b1f6eb5..b4de7bb7 100644 --- a/server/pkg/utils/rand.go +++ b/server/pkg/utils/stringx/rand.go @@ -1,4 +1,4 @@ -package utils +package stringx import ( "math/rand" @@ -8,7 +8,7 @@ import ( const randChar = "0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // 生成随机字符串 -func RandString(l int) string { +func Rand(l int) string { strList := []byte(randChar) result := []byte{} diff --git a/server/pkg/utils/str.go b/server/pkg/utils/stringx/stringx.go similarity index 89% rename from server/pkg/utils/str.go rename to server/pkg/utils/stringx/stringx.go index 0f5c27b5..70f05c67 100644 --- a/server/pkg/utils/str.go +++ b/server/pkg/utils/stringx/stringx.go @@ -1,4 +1,4 @@ -package utils +package stringx import ( "bytes" @@ -9,17 +9,17 @@ import ( ) // 可判断中文 -func StrLen(str string) int { +func Len(str string) int { return len([]rune(str)) } // 去除字符串左右空字符 -func StrTrim(str string) string { +func Trim(str string) string { return strings.Trim(str, " ") } // 去除字符串左右空字符与\n\r换行回车符 -func StrTrimSpaceAndBr(str string) string { +func TrimSpaceAndBr(str string) string { return strings.TrimFunc(str, func(r rune) bool { s := string(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) { index := UnicodeIndex(temp, "{") ei := UnicodeIndex(temp, "}") + 1 - next := StrTrim(temp[ei:]) + next := Trim(temp[ei:]) nextContain := UnicodeIndex(next, "{") nextIndexValue := next if nextContain != -1 { @@ -106,19 +106,19 @@ func ReverStrTemplate(temp, str string, res map[string]any) { // 如果后面没有内容了,则取字符串的长度即可 var valueLastIndex int if nextIndexValue == "" { - valueLastIndex = StrLen(str) + valueLastIndex = Len(str) } else { valueLastIndex = UnicodeIndex(str, nextIndexValue) } - value := StrTrim(SubString(str, index, valueLastIndex)) + value := Trim(SubString(str, index, valueLastIndex)) res[key] = value // 如果后面的还有需要解析的,则递归调用解析 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 var key string if value == nil { diff --git a/server/pkg/utils/template.go b/server/pkg/utils/stringx/template.go similarity index 96% rename from server/pkg/utils/template.go rename to server/pkg/utils/stringx/template.go index c2becaf9..f006e299 100644 --- a/server/pkg/utils/template.go +++ b/server/pkg/utils/stringx/template.go @@ -1,4 +1,4 @@ -package utils +package stringx import ( "bytes" diff --git a/server/pkg/utils/struct.go b/server/pkg/utils/structx/structx.go similarity index 99% rename from server/pkg/utils/struct.go rename to server/pkg/utils/structx/structx.go index c3b8aede..6e517a27 100644 --- a/server/pkg/utils/struct.go +++ b/server/pkg/utils/structx/structx.go @@ -1,4 +1,4 @@ -package utils +package structx import ( "database/sql" diff --git a/server/pkg/utils/struct_test.go b/server/pkg/utils/structx/structx_test.go similarity index 97% rename from server/pkg/utils/struct_test.go rename to server/pkg/utils/structx/structx_test.go index 4e0da8ca..16ad3045 100644 --- a/server/pkg/utils/struct_test.go +++ b/server/pkg/utils/structx/structx_test.go @@ -1,7 +1,8 @@ -package utils +package structx import ( "fmt" + "mayfly-go/pkg/utils/stringx" "reflect" "strings" "testing" @@ -188,7 +189,7 @@ func TestTemplateResolve(t *testing.T) { d := make(map[string]string) d["Name"] = "黄先生" 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) } diff --git a/server/pkg/utils/time.go b/server/pkg/utils/time.go deleted file mode 100644 index cfd45cff..00000000 --- a/server/pkg/utils/time.go +++ /dev/null @@ -1,7 +0,0 @@ -package utils - -import "time" - -func DefaultTimeFormat(time time.Time) string { - return time.Format("2006-01-02 15:04:05") -} diff --git a/server/pkg/utils/timex/timex.go b/server/pkg/utils/timex/timex.go new file mode 100644 index 00000000..040febb0 --- /dev/null +++ b/server/pkg/utils/timex/timex.go @@ -0,0 +1,7 @@ +package timex + +import "time" + +func DefaultFormat(time time.Time) string { + return time.Format("2006-01-02 15:04:05") +} diff --git a/server/pkg/utils/yml.go b/server/pkg/utils/ymlx/ymlx.go similarity index 97% rename from server/pkg/utils/yml.go rename to server/pkg/utils/ymlx/ymlx.go index f48bfac4..4484e19d 100644 --- a/server/pkg/utils/yml.go +++ b/server/pkg/utils/ymlx/ymlx.go @@ -1,4 +1,4 @@ -package utils +package ymlx import ( "errors"