mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 23:40:24 +08:00
285 lines
8.3 KiB
Go
285 lines
8.3 KiB
Go
package application
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"mayfly-go/internal/es/application/dto"
|
||
"mayfly-go/internal/es/domain/entity"
|
||
"mayfly-go/internal/es/domain/repository"
|
||
"mayfly-go/internal/es/esm/esi"
|
||
"mayfly-go/internal/es/imsg"
|
||
"mayfly-go/internal/pkg/consts"
|
||
tagapp "mayfly-go/internal/tag/application"
|
||
tagdto "mayfly-go/internal/tag/application/dto"
|
||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||
"mayfly-go/pkg/base"
|
||
"mayfly-go/pkg/errorx"
|
||
"mayfly-go/pkg/model"
|
||
"mayfly-go/pkg/pool"
|
||
"mayfly-go/pkg/utils/collx"
|
||
"mayfly-go/pkg/utils/stringx"
|
||
"mayfly-go/pkg/utils/structx"
|
||
"time"
|
||
)
|
||
|
||
type Instance interface {
|
||
base.App[*entity.EsInstance]
|
||
// GetPageList 分页获取数据库实例
|
||
GetPageList(condition *entity.InstanceQuery, orderBy ...string) (*model.PageResult[*entity.EsInstance], error)
|
||
|
||
// DoConn 获取连接并执行函数
|
||
DoConn(instanceId uint64, fn func(*esi.EsConn) error) error
|
||
|
||
TestConn(instance *entity.EsInstance, ac *tagentity.ResourceAuthCert) (map[string]any, error)
|
||
|
||
SaveInst(ctx context.Context, d *dto.SaveEsInstance) (uint64, error)
|
||
|
||
Delete(ctx context.Context, instanceId uint64) error
|
||
}
|
||
|
||
var _ Instance = &instanceAppImpl{}
|
||
|
||
var connPool = make(map[uint64]pool.Pool)
|
||
|
||
type instanceAppImpl struct {
|
||
base.AppImpl[*entity.EsInstance, repository.EsInstance]
|
||
|
||
tagApp tagapp.TagTree `inject:"T"`
|
||
resourceAuthCertApp tagapp.ResourceAuthCert `inject:"T"`
|
||
}
|
||
|
||
// GetPageList 分页获取数据库实例
|
||
func (app *instanceAppImpl) GetPageList(condition *entity.InstanceQuery, orderBy ...string) (*model.PageResult[*entity.EsInstance], error) {
|
||
return app.GetRepo().GetInstanceList(condition, orderBy...)
|
||
}
|
||
|
||
func (app *instanceAppImpl) DoConn(instanceId uint64, fn func(*esi.EsConn) error) error {
|
||
// 通过实例id获取实例连接信息
|
||
p, err := app.getPool(instanceId)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
// 从连接池中获取一个可用的连接
|
||
c, err := p.Get()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
ec := c.(*esi.EsConn)
|
||
|
||
// 用完后放回连接池
|
||
defer p.Put(c)
|
||
|
||
return fn(ec)
|
||
}
|
||
|
||
func (app *instanceAppImpl) getPool(instanceId uint64) (pool.Pool, error) {
|
||
// 获取连接池,如果没有,则创建一个
|
||
if p, ok := connPool[instanceId]; !ok {
|
||
var err error
|
||
p, err = pool.NewChannelPool(&pool.Config{
|
||
InitialCap: 1, //资源池初始连接数
|
||
MaxCap: 10, //最大空闲连接数
|
||
MaxIdle: 10, //最大并发连接数
|
||
IdleTimeout: 10 * time.Minute, // 连接最大空闲时间,过期则失效
|
||
Factory: func() (interface{}, error) {
|
||
return app.createConn(instanceId)
|
||
},
|
||
Close: func(v interface{}) error {
|
||
return v.(*esi.EsConn).Close()
|
||
},
|
||
Ping: func(v interface{}) error {
|
||
return v.(*esi.EsConn).Ping()
|
||
},
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
connPool[instanceId] = p
|
||
return p, nil
|
||
} else {
|
||
return p, nil
|
||
}
|
||
}
|
||
func (app *instanceAppImpl) createConn(instanceId uint64) (*esi.EsConn, error) {
|
||
// 缓存不存在,则重新连接
|
||
instance, err := app.GetById(instanceId)
|
||
if err != nil {
|
||
return nil, errorx.NewBiz("es instance not found")
|
||
}
|
||
|
||
ei, err := app.ToEsInfo(instance, nil)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
ei.CodePath = app.tagApp.ListTagPathByTypeAndCode(int8(tagentity.TagTypeEsInstance), instance.Code)
|
||
|
||
conn, _, err := ei.Conn()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
// 缓存连接信息
|
||
return conn, nil
|
||
}
|
||
|
||
func (app *instanceAppImpl) ToEsInfo(instance *entity.EsInstance, ac *tagentity.ResourceAuthCert) (*esi.EsInfo, error) {
|
||
ei := new(esi.EsInfo)
|
||
ei.InstanceId = instance.Id
|
||
structx.Copy(ei, instance)
|
||
ei.OriginUrl = fmt.Sprintf("http://%s:%d", instance.Host, instance.Port)
|
||
|
||
if ac != nil {
|
||
if ac.Ciphertext == "" && ac.Name != "" {
|
||
ac1, err := app.resourceAuthCertApp.GetAuthCert(ac.Name)
|
||
if err == nil {
|
||
ac = ac1
|
||
}
|
||
}
|
||
} else {
|
||
if instance.Code != "" {
|
||
ac2, err := app.resourceAuthCertApp.GetResourceAuthCert(tagentity.TagTypeEsInstance, instance.Code)
|
||
if err == nil {
|
||
ac = ac2
|
||
}
|
||
}
|
||
}
|
||
|
||
if ac != nil && ac.Ciphertext != "" {
|
||
ei.Username = ac.Username
|
||
ei.Password = ac.Ciphertext
|
||
}
|
||
|
||
return ei, nil
|
||
}
|
||
|
||
func (app *instanceAppImpl) TestConn(instance *entity.EsInstance, ac *tagentity.ResourceAuthCert) (map[string]any, error) {
|
||
instance.Network = instance.GetNetwork()
|
||
|
||
ei, err := app.ToEsInfo(instance, ac)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
_, res, err := ei.Conn()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return res, nil
|
||
|
||
}
|
||
|
||
func (app *instanceAppImpl) SaveInst(ctx context.Context, instance *dto.SaveEsInstance) (uint64, error) {
|
||
instanceEntity := instance.EsInstance
|
||
// 默认tcp连接
|
||
instanceEntity.Network = instanceEntity.GetNetwork()
|
||
resourceType := consts.ResourceTypeEsInstance
|
||
authCerts := instance.AuthCerts
|
||
tagCodePaths := instance.TagCodePaths
|
||
|
||
// 查找是否存在该库
|
||
oldInstance := &entity.EsInstance{
|
||
Host: instanceEntity.Host,
|
||
Port: instanceEntity.Port,
|
||
SshTunnelMachineId: instanceEntity.SshTunnelMachineId,
|
||
}
|
||
|
||
err := app.GetByCond(oldInstance)
|
||
if instanceEntity.Id == 0 {
|
||
if err == nil {
|
||
return 0, errorx.NewBizI(ctx, imsg.ErrEsInstExist)
|
||
}
|
||
instanceEntity.Code = stringx.Rand(10)
|
||
|
||
return instanceEntity.Id, app.Tx(ctx, func(ctx context.Context) error {
|
||
return app.Insert(ctx, instanceEntity)
|
||
}, func(ctx context.Context) error {
|
||
return app.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
|
||
ResourceCode: instanceEntity.Code,
|
||
ResourceType: tagentity.TagType(resourceType),
|
||
AuthCerts: authCerts,
|
||
})
|
||
}, func(ctx context.Context) error {
|
||
return app.tagApp.SaveResourceTag(ctx, &tagdto.SaveResourceTag{
|
||
ResourceTag: app.genEsInstanceResourceTag(instanceEntity, authCerts),
|
||
ParentTagCodePaths: tagCodePaths,
|
||
})
|
||
})
|
||
}
|
||
|
||
// 如果存在该库,则校验修改的库是否为该库
|
||
if err == nil {
|
||
if oldInstance.Id != instanceEntity.Id {
|
||
return 0, errorx.NewBizI(ctx, imsg.ErrEsInstExist)
|
||
}
|
||
} else {
|
||
// 根据host等未查到旧数据,则需要根据id重新获取,因为后续需要使用到code
|
||
oldInstance, err = app.GetById(instanceEntity.Id)
|
||
if err != nil {
|
||
return 0, errorx.NewBiz("db instance not found")
|
||
}
|
||
}
|
||
|
||
return oldInstance.Id, app.Tx(ctx, func(ctx context.Context) error {
|
||
return app.UpdateById(ctx, instanceEntity)
|
||
}, func(ctx context.Context) error {
|
||
return app.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
|
||
ResourceCode: oldInstance.Code,
|
||
ResourceType: tagentity.TagType(resourceType),
|
||
AuthCerts: authCerts,
|
||
})
|
||
}, func(ctx context.Context) error {
|
||
if instanceEntity.Name != oldInstance.Name {
|
||
if err := app.tagApp.UpdateTagName(ctx, tagentity.TagTypeDbInstance, oldInstance.Code, instanceEntity.Name); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
return app.tagApp.SaveResourceTag(ctx, &tagdto.SaveResourceTag{
|
||
ResourceTag: app.genEsInstanceResourceTag(oldInstance, authCerts),
|
||
ParentTagCodePaths: tagCodePaths,
|
||
})
|
||
})
|
||
}
|
||
|
||
func (app *instanceAppImpl) genEsInstanceResourceTag(ei *entity.EsInstance, authCerts []*tagentity.ResourceAuthCert) *tagdto.ResourceTag {
|
||
|
||
// 授权证书对应的tag
|
||
authCertTags := collx.ArrayMap[*tagentity.ResourceAuthCert, *tagdto.ResourceTag](authCerts, func(val *tagentity.ResourceAuthCert) *tagdto.ResourceTag {
|
||
return &tagdto.ResourceTag{
|
||
Code: val.Name,
|
||
Name: val.Username,
|
||
Type: tagentity.TagTypeAuthCert,
|
||
}
|
||
})
|
||
|
||
// es实例
|
||
return &tagdto.ResourceTag{
|
||
Code: ei.Code,
|
||
Name: ei.Name,
|
||
Type: tagentity.TagTypeEsInstance,
|
||
Children: authCertTags,
|
||
}
|
||
}
|
||
|
||
func (app *instanceAppImpl) Delete(ctx context.Context, instanceId uint64) error {
|
||
instance, err := app.GetById(instanceId)
|
||
if err != nil {
|
||
return errorx.NewBiz("db instnace not found")
|
||
}
|
||
|
||
return app.Tx(ctx, func(ctx context.Context) error {
|
||
// 删除该实例
|
||
return app.DeleteById(ctx, instanceId)
|
||
}, func(ctx context.Context) error {
|
||
// 删除该实例关联的授权凭证信息
|
||
return app.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
|
||
ResourceCode: instance.Code,
|
||
ResourceType: tagentity.TagType(consts.ResourceTypeEsInstance),
|
||
})
|
||
}, func(ctx context.Context) error {
|
||
// 删除该实例关联的tag信息
|
||
return app.tagApp.DeleteTagByParam(ctx, &tagdto.DelResourceTag{
|
||
ResourceCode: instance.Code,
|
||
ResourceType: tagentity.TagType(consts.ResourceTypeEsInstance),
|
||
})
|
||
})
|
||
}
|