Files
mayfly-go/server/internal/mongo/application/mongo_app.go

220 lines
5.7 KiB
Go
Raw Normal View History

2022-05-17 20:23:08 +08:00
package application
import (
"context"
2022-11-18 17:52:30 +08:00
"fmt"
"mayfly-go/internal/constant"
2022-09-09 18:26:08 +08:00
machineapp "mayfly-go/internal/machine/application"
"mayfly-go/internal/machine/infrastructure/machine"
"mayfly-go/internal/mongo/domain/entity"
"mayfly-go/internal/mongo/domain/repository"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/cache"
"mayfly-go/pkg/global"
"mayfly-go/pkg/model"
"mayfly-go/pkg/utils"
"net"
"regexp"
2022-05-17 20:23:08 +08:00
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type Mongo interface {
// 分页获取机器脚本信息列表
2022-10-26 20:49:29 +08:00
GetPageList(condition *entity.MongoQuery, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult
2022-05-17 20:23:08 +08:00
2022-10-26 20:49:29 +08:00
Count(condition *entity.MongoQuery) int64
2022-05-17 20:23:08 +08:00
// 根据条件获取
GetBy(condition *entity.Mongo, cols ...string) error
// 根据id获取
GetById(id uint64, cols ...string) *entity.Mongo
Save(entity *entity.Mongo)
// 删除数据库信息
Delete(id uint64)
// 获取mongo连接client
// @param id mongo id
GetMongoCli(id uint64) *mongo.Client
}
2022-09-09 18:26:08 +08:00
func newMongoAppImpl(mongoRepo repository.Mongo) Mongo {
return &mongoAppImpl{
mongoRepo: mongoRepo,
}
2022-05-17 20:23:08 +08:00
}
2022-09-09 18:26:08 +08:00
type mongoAppImpl struct {
mongoRepo repository.Mongo
2022-05-17 20:23:08 +08:00
}
// 分页获取数据库信息列表
2022-10-26 20:49:29 +08:00
func (d *mongoAppImpl) GetPageList(condition *entity.MongoQuery, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult {
2022-05-17 20:23:08 +08:00
return d.mongoRepo.GetList(condition, pageParam, toEntity, orderBy...)
}
2022-10-26 20:49:29 +08:00
func (d *mongoAppImpl) Count(condition *entity.MongoQuery) int64 {
2022-05-17 20:23:08 +08:00
return d.mongoRepo.Count(condition)
}
// 根据条件获取
func (d *mongoAppImpl) GetBy(condition *entity.Mongo, cols ...string) error {
return d.mongoRepo.Get(condition, cols...)
}
// 根据id获取
func (d *mongoAppImpl) GetById(id uint64, cols ...string) *entity.Mongo {
return d.mongoRepo.GetById(id, cols...)
}
func (d *mongoAppImpl) Delete(id uint64) {
d.mongoRepo.Delete(id)
DeleteMongoCache(id)
}
func (d *mongoAppImpl) Save(m *entity.Mongo) {
if m.Id == 0 {
d.mongoRepo.Insert(m)
} else {
// 先关闭连接
DeleteMongoCache(m.Id)
d.mongoRepo.Update(m)
}
}
func (d *mongoAppImpl) GetMongoCli(id uint64) *mongo.Client {
mongoInstance, err := GetMongoInstance(id, func(u uint64) *entity.Mongo {
mongo := d.GetById(u)
2022-05-17 20:23:08 +08:00
biz.NotNil(mongo, "mongo信息不存在")
return mongo
2022-05-17 20:23:08 +08:00
})
biz.ErrIsNilAppendErr(err, "连接mongo失败: %s")
return mongoInstance.Cli
2022-05-17 20:23:08 +08:00
}
// -----------------------------------------------------------
// mongo客户端连接缓存指定时间内没有访问则会被关闭
var mongoCliCache = cache.NewTimedCache(constant.MongoConnExpireTime, 5*time.Second).
2022-05-17 20:23:08 +08:00
WithUpdateAccessTime(true).
OnEvicted(func(key interface{}, value interface{}) {
global.Log.Info("删除mongo连接缓存: id = ", key)
value.(*MongoInstance).Close()
2022-05-17 20:23:08 +08:00
})
func init() {
machine.AddCheckSshTunnelMachineUseFunc(func(machineId int) bool {
// 遍历所有mongo连接实例若存在redis实例使用该ssh隧道机器则返回true表示还在使用中...
items := mongoCliCache.Items()
for _, v := range items {
2022-11-18 17:52:30 +08:00
if v.Value.(*MongoInstance).Info.SshTunnelMachineId == machineId {
return true
}
}
return false
})
}
// 获取mongo的连接实例
func GetMongoInstance(mongoId uint64, getMongoEntity func(uint64) *entity.Mongo) (*MongoInstance, error) {
mi, err := mongoCliCache.ComputeIfAbsent(mongoId, func(_ interface{}) (interface{}, error) {
c, err := connect(getMongoEntity(mongoId))
2022-05-17 20:23:08 +08:00
if err != nil {
return nil, err
}
return c, nil
})
if mi != nil {
return mi.(*MongoInstance), err
2022-05-17 20:23:08 +08:00
}
return nil, err
}
func DeleteMongoCache(mongoId uint64) {
mongoCliCache.Delete(mongoId)
}
2022-11-18 17:52:30 +08:00
type MongoInfo struct {
Id uint64
2022-11-18 17:52:30 +08:00
Name string
2022-10-26 20:49:29 +08:00
TagPath string
SshTunnelMachineId int // ssh隧道机器id
2022-11-18 17:52:30 +08:00
}
func (m *MongoInfo) GetLogDesc() string {
return fmt.Sprintf("Mongo[id=%d, tag=%s, name=%s]", m.Id, m.TagPath, m.Name)
}
type MongoInstance struct {
Id uint64
Info *MongoInfo
Cli *mongo.Client
}
func (mi *MongoInstance) Close() {
if mi.Cli != nil {
if err := mi.Cli.Disconnect(context.Background()); err != nil {
global.Log.Errorf("关闭mongo实例[%d]连接失败: %s", mi.Id, err)
}
mi.Cli = nil
}
}
2022-05-17 20:23:08 +08:00
// 连接mongo并返回client
func connect(me *entity.Mongo) (*MongoInstance, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
2022-05-17 20:23:08 +08:00
defer cancel()
2022-11-18 17:52:30 +08:00
mongoInstance := &MongoInstance{Id: me.Id, Info: toMongiInfo(me)}
mongoOptions := options.Client().ApplyURI(me.Uri).
SetMaxPoolSize(1)
// 启用ssh隧道则连接隧道机器
if me.SshTunnelMachineId > 0 {
mongoOptions.SetDialer(&MongoSshDialer{machineId: me.SshTunnelMachineId})
}
client, err := mongo.Connect(ctx, mongoOptions)
2022-05-17 20:23:08 +08:00
if err != nil {
mongoInstance.Close()
2022-05-17 20:23:08 +08:00
return nil, err
}
if err = client.Ping(context.TODO(), nil); err != nil {
mongoInstance.Close()
2022-05-17 20:23:08 +08:00
return nil, err
}
global.Log.Infof("连接mongo: %s", func(str string) string {
reg := regexp.MustCompile(`(^mongodb://.+?:)(.+)(@.+$)`)
return reg.ReplaceAllString(str, `${1}****${3}`)
}(me.Uri))
mongoInstance.Cli = client
return mongoInstance, err
}
2022-11-18 17:52:30 +08:00
func toMongiInfo(me *entity.Mongo) *MongoInfo {
mi := new(MongoInfo)
utils.Copy(mi, me)
return mi
}
type MongoSshDialer struct {
machineId int
}
func (sd *MongoSshDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
2022-09-09 18:26:08 +08:00
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
} else {
return nil, err
}
2022-05-17 20:23:08 +08:00
}