Compare commits

4 Commits

Author SHA1 Message Date
Coder慌
4836a770c4 !139 feat(es):增加ES实例中对HTTP/HTTPS协议的支持,默认使用HTTP协议,使用https时默认证书免校验
Merge pull request !139 from davidathena/dev
2025-10-28 11:25:47 +00:00
fudawei
e6c89fad1b feat(es):增加ES实例中对HTTPS协议的支持,默认证书免校验 2025-10-23 15:29:27 +08:00
meilin.huang
dba19b1e66 fix: editor提示被遮挡问题修复等 2025-10-18 11:21:33 +08:00
davidathena
4e30bdb7cc !138 fix: 后端数据连接断开后报空指针异常后程序中断问题
* fix(connection):fix the bug for nil error in connection when connection reset
* fix(sqleditor): fix the spell error in sql editor
2025-10-18 03:15:25 +00:00
40 changed files with 202 additions and 77 deletions

View File

@@ -11,14 +11,14 @@
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.2",
"@logicflow/core": "^2.1.2",
"@logicflow/extension": "^2.1.3",
"@logicflow/core": "^2.1.3",
"@logicflow/extension": "^2.1.5",
"@vueuse/core": "^13.9.0",
"@xterm/addon-fit": "^0.10.0",
"@xterm/addon-search": "^0.15.0",
"@xterm/addon-web-links": "^0.11.0",
"@xterm/xterm": "^5.5.0",
"asciinema-player": "^3.11.0",
"asciinema-player": "^3.11.1",
"axios": "^1.6.2",
"clipboard": "^2.0.11",
"crypto-js": "^4.2.0",
@@ -40,7 +40,7 @@
"uuid": "^13.0.0",
"vue": "^v3.5.22",
"vue-i18n": "^11.1.12",
"vue-router": "^4.5.1",
"vue-router": "^4.6.3",
"vuedraggable": "^4.1.0"
},
"devDependencies": {

View File

@@ -155,6 +155,7 @@ const defaultOptions = {
scrollBeyondLastLine: false,
lineNumbers: 'on',
lineNumbersMinChars: 3,
fixedOverflowWidgets: true, // 使弹出层不被容器限制
} as editor.IStandaloneEditorConstructionOptions;
const monacoTextareaRef: Ref<any> = useTemplateRef('monacoTextareaRef');

View File

@@ -1,6 +1,7 @@
export default {
es: {
keywordPlaceholder: 'host / name / code',
protocol: 'Protocol',
port: 'Port',
size: 'size',
docs: 'docs',

View File

@@ -1,6 +1,7 @@
export default {
es: {
keywordPlaceholder: 'host / 名称 / 编号',
protocol: '协议',
port: '端口',
size: '存储大小',
docs: '文档数',

View File

@@ -138,9 +138,8 @@ onBeforeRouteUpdate((to) => {
.horizontal-menu :deep(.el-sub-menu__title) {
margin: 0 5px !important;
justify-content: center;
max-width: 150px;
min-width: 120px; // 统一最小宽度
width: fit-content;
text-align: center; // 使文字居中对齐
padding: 0 8px !important; // 统一内边距
padding: 0 16px !important; // 统一内边距
}
</style>

View File

@@ -88,7 +88,7 @@
</template>
<el-row>
<span v-if="dt.hasUpdatedFileds" class="mt-1">
<span v-if="dt.hasUpdatedFields" class="mt-1">
<span>
<el-link type="success" underline="never" @click="submitUpdateFields(dt)"
><span style="font-size: 12px">{{ $t('common.submit') }}</span></el-link
@@ -200,7 +200,7 @@ class ExecResTab {
/**
* 是否有更新字段
*/
hasUpdatedFileds: boolean;
hasUpdatedFields: boolean;
errorMsg: string;
@@ -783,7 +783,7 @@ const getUploadSqlFileUrl = () => {
const changeUpdatedField = (updatedFields: any, dt: ExecResTab) => {
// 如果存在要更新字段,则显示提交和取消按钮
dt.hasUpdatedFileds = updatedFields && updatedFields.size > 0;
dt.hasUpdatedFields = updatedFields && updatedFields.size > 0;
};
/**

View File

@@ -19,6 +19,13 @@
<el-form-item prop="version" :label="t('common.version')">
<el-input v-model.trim="form.version" auto-complete="off" disabled></el-input>
</el-form-item>
<!-- 增加协议下拉框 http和https默认http-->
<el-form-item prop="protocol" :label="t('es.protocol')">
<el-select v-model="form.protocol" placeholder="http">
<el-option label="http" value="http"></el-option>
<el-option label="https" value="https"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="host" label="Host" required>
<el-col :span="18">
@@ -105,6 +112,7 @@ const DefaultForm = {
id: null,
code: '',
name: null,
protocol: 'http',
host: '',
version: '',
port: 9200,

View File

@@ -34,8 +34,8 @@ require (
github.com/tidwall/gjson v1.18.0
github.com/veops/go-ansiterm v0.0.5
go.mongodb.org/mongo-driver/v2 v2.3.0 // mongo
golang.org/x/crypto v0.42.0 // ssh
golang.org/x/oauth2 v0.31.0
golang.org/x/crypto v0.43.0 // ssh
golang.org/x/oauth2 v0.32.0
golang.org/x/sync v0.17.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1
@@ -118,9 +118,9 @@ require (
golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect
golang.org/x/image v0.31.0 // indirect
golang.org/x/mod v0.28.0 // indirect
golang.org/x/net v0.44.0 // indirect
golang.org/x/sys v0.36.0 // indirect
golang.org/x/text v0.29.0 // indirect
golang.org/x/net v0.45.0 // indirect
golang.org/x/sys v0.37.0 // indirect
golang.org/x/text v0.30.0 // indirect
golang.org/x/tools v0.37.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect
modernc.org/libc v1.66.10 // indirect

View File

@@ -209,7 +209,7 @@ func (d *dbAppImpl) GetDbConnByInstanceId(ctx context.Context, instanceId uint64
return nil, errorx.NewBiz("failed to get database list")
}
if len(dbs) == 0 {
return nil, errorx.NewBiz("DB instance [%d] database is not configured, please configure it first", instanceId)
return nil, errorx.NewBizf("DB instance [%d] database is not configured, please configure it first", instanceId)
}
// 使用该实例关联的已配置数据库中的第一个库进行连接并返回
@@ -308,7 +308,7 @@ func (d *dbAppImpl) DumpDb(ctx context.Context, reqParam *dto.DumpDb) error {
}
if len(tbs) <= 0 {
log(fmt.Sprintf("failed to get table [%s] information: No table information was retrieved", tableName))
return errorx.NewBiz("Failed to get table information: %s", tableName)
return errorx.NewBizf("Failed to get table information: %s", tableName)
}
tableInfo := tbs[0]

View File

@@ -114,7 +114,7 @@ func (app *dataSyncAppImpl) Run(ctx context.Context, id uint64) error {
}
updateStateTask.Id = id
if err := app.UpdateById(ctx, updateStateTask); err != nil {
return errorx.NewBiz("failed to update task running state: %s", err.Error())
return errorx.NewBizf("failed to update task running state: %s", err.Error())
}
// 标记该任务运行中
@@ -184,20 +184,20 @@ func (app *dataSyncAppImpl) doDataSync(ctx context.Context, sql string, task *en
srcConn, err := app.dbApp.GetDbConn(ctx, uint64(task.SrcDbId), task.SrcDbName)
if err != nil {
return errorx.NewBiz("failed to connect to the source database: %s", err.Error())
return errorx.NewBizf("failed to connect to the source database: %s", err.Error())
}
// 获取目标数据库连接
targetConn, err := app.dbApp.GetDbConn(ctx, uint64(task.TargetDbId), task.TargetDbName)
if err != nil {
return errorx.NewBiz("failed to connect to the target database: %s", err.Error())
return errorx.NewBizf("failed to connect to the target database: %s", err.Error())
}
// task.FieldMap为json数组字符串 [{"src":"id","target":"id"}]转为map
var fieldMap []map[string]string
err = json.Unmarshal([]byte(task.FieldMap), &fieldMap)
if err != nil {
return errorx.NewBiz("there was an error parsing the field map json: %s", err.Error())
return errorx.NewBizf("there was an error parsing the field map json: %s", err.Error())
}
// 记录本次同步数据总数
@@ -213,7 +213,7 @@ func (app *dataSyncAppImpl) doDataSync(ctx context.Context, sql string, task *en
targetTableColumns, err := targetConn.GetMetadata().GetColumns(task.TargetTableName)
if err != nil {
return errorx.NewBiz("failed to get target table columns: %s", err.Error())
return errorx.NewBizf("failed to get target table columns: %s", err.Error())
}
targetColumnName2Column := collx.ArrayToMap(targetTableColumns, func(column dbi.Column) string {
return column.ColumnName
@@ -300,7 +300,7 @@ func (app *dataSyncAppImpl) srcData2TargetDb(srcRes []map[string]any, fieldMap [
// 开启本批次执行事务
targetDbTx, err := targetDbConn.Begin()
if err != nil {
return errorx.NewBiz("failed to start the target database transaction: %s", err.Error())
return errorx.NewBizf("failed to start the target database transaction: %s", err.Error())
}
defer func() {
if r := recover(); r != nil {
@@ -320,7 +320,7 @@ func (app *dataSyncAppImpl) srcData2TargetDb(srcRes []map[string]any, fieldMap [
// 如果是mssql暂不手动提交事务否则报错 mssql: The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
if err := targetDbTx.Commit(); err != nil {
if targetDbConn.Info.Type != dbi.ToDbType("mssql") {
return errorx.NewBiz("data synchronization - The target database transaction failed to commit: %s", err.Error())
return errorx.NewBizf("data synchronization - The target database transaction failed to commit: %s", err.Error())
}
}

View File

@@ -300,7 +300,7 @@ func (d *dbSqlExecAppImpl) FlowBizHandle(ctx context.Context, bizHandleParam *fl
execSqlBizForm, err := jsonx.To[*FlowDbExecSqlBizForm](procinst.BizForm)
if err != nil {
return nil, errorx.NewBiz("failed to parse the business form information: %s", err.Error())
return nil, errorx.NewBizf("failed to parse the business form information: %s", err.Error())
}
dbConn, err := d.dbApp.GetDbConn(ctx, execSqlBizForm.DbId, execSqlBizForm.DbName)
@@ -471,7 +471,7 @@ func (d *dbSqlExecAppImpl) doUpdate(ctx context.Context, sqlExecParam *sqlExecPa
nowRec++
res = append(res, row)
if nowRec == maxRec {
return errorx.NewBiz("update SQL - the maximum number of updated queries is exceeded: %d", maxRec)
return errorx.NewBizf("update SQL - the maximum number of updated queries is exceeded: %d", maxRec)
}
return nil
})

View File

@@ -122,12 +122,12 @@ func (app *dbTransferAppImpl) InitCronJob() {
func (app *dbTransferAppImpl) Run(ctx context.Context, taskId uint64) (uint64, error) {
if app.IsRunning(taskId) {
return 0, errorx.NewBiz("the db transfer task [%d] is running, please do not repeat the operation", taskId)
return 0, errorx.NewBizf("the db transfer task [%d] is running, please do not repeat the operation", taskId)
}
task, err := app.GetById(taskId)
if err != nil {
return 0, errorx.NewBiz("db transfer task [%d] not found", taskId)
return 0, errorx.NewBizf("db transfer task [%d] not found", taskId)
}
logId, _ := app.CreateLog(ctx, taskId)

View File

@@ -41,6 +41,15 @@ func (d *DbConn) Close() error {
}
func (d *DbConn) Ping() error {
// 首先检查d是否为nil
if d == nil {
return fmt.Errorf("d is nil")
}
// 然后检查d.db是否为nil这是避免空指针异常的关键
if d.db == nil {
return fmt.Errorf("db is nil")
}
return d.db.Ping()
}

View File

@@ -70,13 +70,13 @@ func (di *DbInfo) Conn(ctx context.Context, meta Meta) (*DbConn, error) {
conn, err := meta.GetSqlDb(ctx, di)
if err != nil {
logx.Errorf("db connection failed: %s:%d/%s, err:%s", di.Host, di.Port, database, err.Error())
return nil, errorx.NewBiz("db connection failed: %s", err.Error())
return nil, errorx.NewBizf("db connection failed: %s", err.Error())
}
err = conn.Ping()
if err != nil {
logx.Errorf("db ping failed: %s:%d/%s, err:%s", di.Host, di.Port, database, err.Error())
return nil, errorx.NewBiz("db connection failed: %s", err.Error())
return nil, errorx.NewBizf("db connection failed: %s", err.Error())
}
dbc := &DbConn{Id: GetDbConnId(di.Id, database), Info: di}

View File

@@ -134,7 +134,7 @@ func (dd *DMMetadata) GetPrimaryKey(tablename string) (string, error) {
return "", err
}
if len(columns) == 0 {
return "", errorx.NewBiz("[%s] 表不存在", tablename)
return "", errorx.NewBizf("[%s] 表不存在", tablename)
}
for _, v := range columns {
if v.IsPrimaryKey {

View File

@@ -129,7 +129,7 @@ func (md *MssqlMetadata) GetPrimaryKey(tablename string) (string, error) {
return "", err
}
if len(columns) == 0 {
return "", errorx.NewBiz("[%s] 表不存在", tablename)
return "", errorx.NewBizf("[%s] 表不存在", tablename)
}
for _, v := range columns {

View File

@@ -125,7 +125,7 @@ func (md *MysqlMetadata) GetPrimaryKey(tablename string) (string, error) {
return "", err
}
if len(columns) == 0 {
return "", errorx.NewBiz("[%s] 表不存在", tablename)
return "", errorx.NewBizf("[%s] 表不存在", tablename)
}
for _, v := range columns {

View File

@@ -148,7 +148,7 @@ func (od *OracleMetadata) GetPrimaryKey(tablename string) (string, error) {
return "", err
}
if len(columns) == 0 {
return "", errorx.NewBiz("[%s] 表不存在", tablename)
return "", errorx.NewBizf("[%s] 表不存在", tablename)
}
for _, v := range columns {
if v.IsPrimaryKey {

View File

@@ -124,7 +124,7 @@ func (pd *PgsqlMetadata) GetPrimaryKey(tablename string) (string, error) {
return "", err
}
if len(columns) == 0 {
return "", errorx.NewBiz("[%s] 表不存在", tablename)
return "", errorx.NewBizf("[%s] 表不存在", tablename)
}
for _, v := range columns {
if v.IsPrimaryKey {

View File

@@ -148,14 +148,14 @@ func (d *Container) ContainerCreate(rc *req.Ctx) {
if err != nil {
_ = cli.DockerClient.ContainerRemove(ctx, containerCreate.Name, container.RemoveOptions{RemoveVolumes: true, Force: true})
panic(errorx.NewBiz("create container failed, err: %v", err))
panic(errorx.NewBizf("create container failed, err: %v", err))
}
logx.Infof("create container %s successful! now check if the container is started and delete the container information if it is not.", containerCreate.Name)
if err := cli.DockerClient.ContainerStart(ctx, con.ID, container.StartOptions{}); err != nil {
_ = cli.DockerClient.ContainerRemove(ctx, containerCreate.Name, container.RemoveOptions{RemoveVolumes: true, Force: true})
panic(errorx.NewBiz("create successful but start failed, err: %v", err))
panic(errorx.NewBizf("create successful but start failed, err: %v", err))
}
}

View File

@@ -6,6 +6,7 @@ import (
type InstanceForm struct {
Id uint64 `json:"id"`
Protocol string `binding:"required" json:"protocol"`
Name string `binding:"required" json:"name"`
Host string `binding:"required" json:"host"`
Port int `binding:"required" json:"port"`

View File

@@ -9,13 +9,14 @@ type InstanceListVO struct {
tagentity.AuthCerts // 授权凭证信息
tagentity.ResourceTags
Id *int64 `json:"id"`
Code string `json:"code"`
Name *string `json:"name"`
Host *string `json:"host"`
Port *int `json:"port"`
Version *string `json:"version"`
Remark *string `json:"remark"`
Id *int64 `json:"id"`
Code string `json:"code"`
Name *string `json:"name"`
Protocol *string `json:"protocol"`
Host *string `json:"host"`
Port *int `json:"port"`
Version *string `json:"version"`
Remark *string `json:"remark"`
CreateTime *time.Time `json:"createTime"`
Creator *string `json:"creator"`

View File

@@ -10,6 +10,7 @@ type EsInstance struct {
Code string `json:"code" gorm:"size:32;not null;"`
Name string `json:"name" gorm:"size:32;not null;"`
Protocol string `json:"protocol" gorm:"size:10;not null;"`
Host string `json:"host" gorm:"size:255;not null;"`
Port int `json:"port"`
Network string `json:"network" gorm:"size:20;"`

View File

@@ -1,6 +1,7 @@
package esi
import (
"crypto/tls"
"fmt"
"mayfly-go/internal/machine/mcm"
"mayfly-go/pkg/logx"
@@ -27,6 +28,15 @@ func (d *EsConn) Close() error {
}
func (d *EsConn) Ping() error {
// 首先检查d是否为nil
if d == nil {
return fmt.Errorf("es connection is nil")
}
// 然后检查d.Info是否为nil这是避免空指针异常的关键
if d.Info == nil {
return fmt.Errorf("es Info is nil")
}
_, err := d.Info.Ping()
return err
}
@@ -43,6 +53,16 @@ func (d *EsConn) StartProxy() error {
d.proxy = httputil.NewSingleHostReverseProxy(targetURL)
// 设置 proxy buffer pool
d.proxy.BufferPool = NewBufferPool()
// Configure TLS to skip certificate verification for non-compliant certificates
if targetURL.Scheme == "https" {
d.proxy.Transport = &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
}
return nil
}

View File

@@ -23,6 +23,7 @@ type EsInfo struct {
InstanceId uint64 // 实例id
Name string
Protocol string // 协议默认http
Host string
Port int
Network string
@@ -58,14 +59,14 @@ func (di *EsInfo) Conn(ctx context.Context) (*EsConn, map[string]any, error) {
err := di.IfUseSshTunnelChangeIpPort(ctx)
if err != nil {
logx.Errorf("es ssh failed: %s, err:%s", di.baseUrl, err.Error())
return nil, nil, errorx.NewBiz("es ssh failed: %s", err.Error())
return nil, nil, errorx.NewBizf("es ssh failed: %s", err.Error())
}
// 尝试获取es版本信息调用接口get /
res, err := di.Ping()
if err != nil {
logx.Errorf("es ping failed: %s, err:%s", di.baseUrl, err.Error())
return nil, nil, errorx.NewBiz("es ping failed: %s", err.Error())
return nil, nil, errorx.NewBizf("es ping failed: %s", err.Error())
}
esc := &EsConn{Id: di.InstanceId, Info: di}
@@ -90,7 +91,14 @@ func (di *EsInfo) Ping() (map[string]any, error) {
// ExecApi 执行api
func (di *EsInfo) ExecApi(method, path string, data any, timeoutSecond ...int) (map[string]any, error) {
request := httpx.NewReq(di.baseUrl + path)
var request *httpx.Req
// Use insecure TLS client for HTTPS connections to handle non-compliant certificates
if di.Protocol == "https" {
request = httpx.NewReqWithInsecureTLS(di.baseUrl + path)
} else {
request = httpx.NewReq(di.baseUrl + path)
}
if di.authorization != "" {
request.Header("Authorization", di.authorization)
}
@@ -111,12 +119,17 @@ func (di *EsInfo) ExecApi(method, path string, data any, timeoutSecond ...int) (
return request.PutObj(data).BodyToMap()
}
return nil, errorx.NewBiz("不支持的请求方法: %s", method)
return nil, errorx.NewBizf("不支持的请求方法: %s", method)
}
// 如果使用了ssh隧道将其host port改变其本地映射host port
func (di *EsInfo) IfUseSshTunnelChangeIpPort(ctx context.Context) error {
// 设置默认协议
if di.Protocol == "" {
di.Protocol = "http"
}
// 开启ssh隧道
if di.SshTunnelMachineId > 0 {
stm, err := GetSshTunnel(ctx, di.SshTunnelMachineId)
@@ -130,9 +143,9 @@ func (di *EsInfo) IfUseSshTunnelChangeIpPort(ctx context.Context) error {
di.Host = exposedIp
di.Port = exposedPort
di.useSshTunnel = true
di.baseUrl = fmt.Sprintf("http://%s:%d", exposedIp, exposedPort)
di.baseUrl = fmt.Sprintf("%s://%s:%d", di.Protocol, exposedIp, exposedPort)
} else {
di.baseUrl = fmt.Sprintf("http://%s:%d", di.Host, di.Port)
di.baseUrl = fmt.Sprintf("%s://%s:%d", di.Protocol, di.Host, di.Port)
}
return nil
}

View File

@@ -312,10 +312,10 @@ func (m *machineAppImpl) ToMachineInfoById(machineId uint64) (*mcm.MachineInfo,
func (m *machineAppImpl) getMachineAndAuthCert(machineId uint64) (*entity.Machine, *tagentity.ResourceAuthCert, error) {
me, err := m.GetById(machineId)
if err != nil {
return nil, nil, errorx.NewBiz("[%d] machine not found", machineId)
return nil, nil, errorx.NewBizf("[%d] machine not found", machineId)
}
if me.Status != entity.MachineStatusEnable && me.Protocol == 1 {
return nil, nil, errorx.NewBiz("[%s] machine has been disable", me.Code)
return nil, nil, errorx.NewBizf("[%s] machine has been disable", me.Code)
}
authCert, err := m.resourceAuthCertApp.GetResourceAuthCert(tagentity.TagTypeMachine, me.Code)

View File

@@ -180,7 +180,7 @@ func (m *machineFileAppImpl) GetDirSize(ctx context.Context, opParam *dto.Machin
//du: cannot access /proc/19087/fdinfo/3: No such file or directory\n
//18G /\n
if res == "" {
return "", errorx.NewBiz("failed to get directory size: %s", err.Error())
return "", errorx.NewBizf("failed to get directory size: %s", err.Error())
}
strs := strings.Split(res, "\n")
res = strs[len(strs)-2]
@@ -247,7 +247,7 @@ func (m *machineFileAppImpl) CreateFile(ctx context.Context, opParam *dto.Machin
}
file, err := sftpCli.Create(path)
if err != nil {
return nil, errorx.NewBiz("failed to create file: %s", err.Error())
return nil, errorx.NewBizf("failed to create file: %s", err.Error())
}
defer file.Close()
return mi, err

View File

@@ -63,7 +63,7 @@ func (m *machineTermOpAppImpl) TermConn(ctx context.Context, cli *mcm.Cli, wsCon
fileKey, wc, saveFileFunc, err := m.fileApp.NewWriter(ctx, "", fmt.Sprintf("mto_%d_%s.cast", termOpRecord.MachineId, timex.TimeNo()))
if err != nil {
return errorx.NewBiz("failed to create a terminal playback log file: %v", err)
return errorx.NewBizf("failed to create a terminal playback log file: %v", err)
}
defer saveFileFunc(&err)

View File

@@ -63,7 +63,7 @@ func (c *Cli) GetSftpCli() (*sftp.Client, error) {
if sftpclient == nil {
sc, serr := sftp.NewClient(c.sshClient)
if serr != nil {
return nil, errorx.NewBiz("failed to obtain the sftp client: %s", serr.Error())
return nil, errorx.NewBizf("failed to obtain the sftp client: %s", serr.Error())
}
sftpclient = sc
c.sftpClient = sftpclient

View File

@@ -56,7 +56,7 @@ func (mi *MachineInfo) Conn(ctx context.Context) (*Cli, error) {
// 如果使用了ssh隧道则修改机器ip port为暴露的ip port
err := mi.IfUseSshTunnelChangeIpPort(ctx, false)
if err != nil {
return nil, errorx.NewBiz("ssh tunnel connection failed: %s", err.Error())
return nil, errorx.NewBizf("ssh tunnel connection failed: %s", err.Error())
}
cli := &Cli{Info: mi}

View File

@@ -2,6 +2,7 @@ package mgm
import (
"context"
"fmt"
"mayfly-go/pkg/logx"
"go.mongodb.org/mongo-driver/v2/mongo"
@@ -28,5 +29,14 @@ func (mc *MongoConn) Close() error {
}
func (mc *MongoConn) Ping() error {
// 首先检查mc是否为nil
if mc == nil {
return fmt.Errorf("mc connection is nil")
}
// 然后检查mc.Cli是否为nil这是避免空指针异常的关键
if mc.Cli == nil {
return fmt.Errorf("mc client is nil")
}
return mc.Cli.Ping(context.Background(), nil)
}

View File

@@ -254,7 +254,7 @@ func (r *redisAppImpl) FlowBizHandle(ctx context.Context, bizHandleParam *flowap
runCmdParam, err := jsonx.To[*FlowRedisRunCmdBizForm](procinst.BizForm)
if err != nil {
return nil, errorx.NewBiz("failed to parse the business form information: %s", err.Error())
return nil, errorx.NewBizf("failed to parse the business form information: %s", err.Error())
}
redisConn, err := r.GetRedisConn(ctx, runCmdParam.Id, runCmdParam.Db)

View File

@@ -2,6 +2,7 @@ package rdm
import (
"context"
"fmt"
"mayfly-go/pkg/errorx"
"mayfly-go/pkg/logx"
@@ -41,7 +42,19 @@ func (r *RedisConn) Close() error {
}
func (r *RedisConn) Ping() error {
_, err := r.Cli.Ping(context.Background()).Result()
// 首先检查r是否为nil
if r == nil {
return fmt.Errorf("redis connection is nil")
}
// 然后检查r.Cli是否为nil这是避免空指针异常的关键
if r.Cli == nil {
return fmt.Errorf("redis client is nil")
}
cmd := r.Cli.Ping(context.Background())
if cmd == nil {
return fmt.Errorf("the ping cmd is nil")
}
_, err := cmd.Result()
return err
}

View File

@@ -70,7 +70,7 @@ func (re *RedisInfo) connStandalone() (*RedisConn, error) {
_, e := cli.Ping(context.Background()).Result()
if e != nil {
cli.Close()
return nil, errorx.NewBiz("redis standalone connection failed: %s", e.Error())
return nil, errorx.NewBizf("redis standalone connection failed: %s", e.Error())
}
logx.Infof("redis standalone connection: %s/%d", re.Host, re.Db)
@@ -95,7 +95,7 @@ func (re *RedisInfo) connCluster() (*RedisConn, error) {
_, e := cli.Ping(context.Background()).Result()
if e != nil {
cli.Close()
return nil, errorx.NewBiz("redis cluster connection failed: %s", e.Error())
return nil, errorx.NewBizf("redis cluster connection failed: %s", e.Error())
}
logx.Infof("redis cluster connection: %s/%d", re.Host, re.Db)
@@ -128,7 +128,7 @@ func (re *RedisInfo) connSentinel() (*RedisConn, error) {
_, e := cli.Ping(context.Background()).Result()
if e != nil {
cli.Close()
return nil, errorx.NewBiz("redis sentinel connection failed: %s", e.Error())
return nil, errorx.NewBizf("redis sentinel connection failed: %s", e.Error())
}
logx.Infof("redis sentinel connection: %s/%d", re.Host, re.Db)

View File

@@ -121,7 +121,7 @@ func (r *resourceAuthCertAppImpl) RelateAuthCert(ctx context.Context, params *dt
existNameAc := &entity.ResourceAuthCert{Name: addAcName}
if r.GetByCond(existNameAc) == nil && existNameAc.ResourceCode != resourceCode {
return errorx.NewBiz("The name of the authorization credential cannot be repeated: [%s]", addAcName)
return errorx.NewBizf("The name of the authorization credential cannot be repeated: [%s]", addAcName)
}
addAuthCerts = append(addAuthCerts, addAc)

View File

@@ -210,7 +210,7 @@ func (p *tagTreeAppImpl) RelateTagsByCodeAndType(ctx context.Context, param *dto
if len(parentTagCodePaths) == 0 {
// 不满足满足条件的标签
return errorx.NewBiz("There is no tag that satisfies [type=%d, code=%s]", parentTagType, parentTagCode)
return errorx.NewBizf("There is no tag that satisfies [type=%d, code=%s]", parentTagType, parentTagCode)
}
for _, tag := range param.Tags {

View File

@@ -20,6 +20,7 @@ func V1_10() []*gormigrate.Migration {
migrations = append(migrations, V1_10_1()...)
migrations = append(migrations, V1_10_2()...)
migrations = append(migrations, V1_10_3()...)
migrations = append(migrations, V1_10_4()...)
return migrations
}
@@ -326,3 +327,28 @@ func V1_10_3() []*gormigrate.Migration {
},
}
}
func V1_10_4() []*gormigrate.Migration {
return []*gormigrate.Migration{
{
ID: "20251023-v1.10.4",
Migrate: func(tx *gorm.DB) error {
// 给EsInstance表添加protocol列默认值为http, 20251023,fudawei
if !tx.Migrator().HasColumn(&esentity.EsInstance{}, "protocol") {
// 先添加可为空的列
if err := tx.Exec("ALTER TABLE t_es_instance ADD COLUMN protocol VARCHAR(10) DEFAULT 'http'").Error; err != nil {
return err
}
// 更新所有现有记录为默认值http
if err := tx.Exec("UPDATE t_es_instance SET protocol = 'http' WHERE protocol IS NULL OR protocol = ''").Error; err != nil {
return err
}
}
return nil
},
Rollback: func(tx *gorm.DB) error {
return nil
},
},
}
}

View File

@@ -21,7 +21,7 @@ func ErrIsNil(err error, msgAndParams ...any) {
panic(errorx.NewBiz(err.Error()))
}
panic(errorx.NewBiz(msgAndParams[0].(string), msgAndParams[1:]...))
panic(errorx.NewBizf(msgAndParams[0].(string), msgAndParams[1:]...))
}
}
@@ -43,7 +43,7 @@ func ErrIsNilI(ctx context.Context, err error, msgId i18n.MsgId, attrs ...any) {
func ErrNotNil(err error, msg string, params ...any) {
if err == nil {
panic(errorx.NewBiz(msg, params...))
panic(errorx.NewBizf(msg, params...))
}
}
@@ -53,7 +53,7 @@ func ErrNotNil(err error, msg string, params ...any) {
// biz.ErrIsNilAppendErr(err, "xxxx: %s")
func ErrIsNilAppendErr(err error, msg string) {
if err != nil {
panic(errorx.NewBiz(msg, err.Error()))
panic(errorx.NewBizf(msg, err.Error()))
}
}
@@ -63,13 +63,13 @@ func ErrIsNilAppendErr(err error, msg string) {
// biz.ErrIsNilAppendErr(err, "xxxx: %s")
func ErrIsNilAppendErrI(ctx context.Context, err error, msgId i18n.MsgId) {
if err != nil {
panic(errorx.NewBiz(i18n.TC(ctx, msgId), err.Error()))
panic(errorx.NewBizf(i18n.TC(ctx, msgId), err.Error()))
}
}
func IsTrue(exp bool, msg string, params ...any) {
if !exp {
panic(errorx.NewBiz(msg, params...))
panic(errorx.NewBizf(msg, params...))
}
}
@@ -87,19 +87,19 @@ func IsTrueBy(exp bool, err *errorx.BizError) {
func NotEmpty(str string, msg string, params ...any) {
if str == "" {
panic(errorx.NewBiz(msg, params...))
panic(errorx.NewBizf(msg, params...))
}
}
func NotNil(data any, msg string, params ...any) {
if reflect.ValueOf(data).IsNil() {
panic(errorx.NewBiz(msg, params...))
panic(errorx.NewBizf(msg, params...))
}
}
func NotBlank(data any, msg string, params ...any) {
if anyx.IsBlank(data) {
panic(errorx.NewBiz(msg, params...))
panic(errorx.NewBizf(msg, params...))
}
}

View File

@@ -35,8 +35,13 @@ func (e BizError) String() string {
}
// NewBiz 创建业务逻辑错误结构体,默认为业务逻辑错误
func NewBiz(msg string, formatValues ...any) *BizError {
return &BizError{code: BizErr.code, err: fmt.Sprintf(msg, formatValues...)}
func NewBiz(msg string) *BizError {
return &BizError{code: BizErr.code, err: msg}
}
// NewBizf 创建业务逻辑错误结构体,可设置格式化参数
func NewBizf(format string, formatValues ...any) *BizError {
return NewBiz(fmt.Sprintf(format, formatValues...))
}
// NewBizI 使用i18n的msgId创建业务逻辑错误结构体默认为业务逻辑错误 (使用ctx中的国际化语言)
@@ -47,7 +52,12 @@ func NewBizI(ctx context.Context, msgId i18n.MsgId, attrs ...any) *BizError {
return &BizError{code: BizErr.code, err: i18n.TC(ctx, msgId, attrs...)}
}
// 创建业务逻辑错误结构体可设置指定错误code
func NewBizCode(code int16, msg string, formats ...any) *BizError {
return &BizError{code: code, err: fmt.Sprintf(msg, formats...)}
// NewBizCode 创建业务逻辑错误结构体可设置指定错误code
func NewBizCode(code int16, msg string) *BizError {
return &BizError{code: code, err: msg}
}
// NewBizCodef 创建业务逻辑错误结构体可设置指定错误code并且支持格式化参数
func NewBizCodef(code int16, format string, formats ...any) *BizError {
return NewBizCode(code, fmt.Sprintf(format, formats...))
}

View File

@@ -2,6 +2,7 @@ package httpx
import (
"bytes"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
@@ -41,6 +42,16 @@ func NewReq(url string) *Req {
return &Req{url: url, client: http.Client{}}
}
// 创建一个请求(不验证TLS证书)
func NewReqWithInsecureTLS(url string) *Req {
transport := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
return &Req{url: url, client: http.Client{Transport: transport}}
}
func (r *Req) Url(url string) *Req {
r.url = url
return r