refactor: 后端包结构重构、去除无用的文件

This commit is contained in:
meilin.huang
2022-06-02 17:41:11 +08:00
parent 51d06ab206
commit b2dc9dff0b
234 changed files with 749 additions and 816 deletions

View File

@@ -0,0 +1,289 @@
package api
import (
"fmt"
"io/ioutil"
"mayfly-go/internal/devops/api/form"
"mayfly-go/internal/devops/api/vo"
"mayfly-go/internal/devops/application"
"mayfly-go/internal/devops/domain/entity"
sysApplication "mayfly-go/internal/sys/application"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/ctx"
"mayfly-go/pkg/ginx"
"mayfly-go/pkg/model"
"mayfly-go/pkg/utils"
"mayfly-go/pkg/ws"
"strconv"
"strings"
"github.com/gin-gonic/gin"
)
type Db struct {
DbApp application.Db
MsgApp sysApplication.Msg
ProjectApp application.Project
}
// @router /api/dbs [get]
func (d *Db) Dbs(rc *ctx.ReqCtx) {
g := rc.GinCtx
m := &entity.Db{EnvId: uint64(ginx.QueryInt(g, "envId", 0)),
ProjectId: uint64(ginx.QueryInt(g, "projectId", 0)),
}
m.CreatorId = rc.LoginAccount.Id
rc.ResData = d.DbApp.GetPageList(m, ginx.GetPageParam(rc.GinCtx), new([]vo.SelectDataDbVO))
}
func (d *Db) Save(rc *ctx.ReqCtx) {
form := &form.DbForm{}
ginx.BindJsonAndValid(rc.GinCtx, form)
rc.ReqParam = form
db := new(entity.Db)
utils.Copy(db, form)
db.SetBaseInfo(rc.LoginAccount)
d.DbApp.Save(db)
}
func (d *Db) DeleteDb(rc *ctx.ReqCtx) {
d.DbApp.Delete(GetDbId(rc.GinCtx))
}
func (d *Db) TableInfos(rc *ctx.ReqCtx) {
rc.ResData = d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx)).GetTableInfos()
}
func (d *Db) TableIndex(rc *ctx.ReqCtx) {
tn := rc.GinCtx.Query("tableName")
biz.NotEmpty(tn, "tableName不能为空")
rc.ResData = d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx)).GetTableIndex(tn)
}
func (d *Db) GetCreateTableDdl(rc *ctx.ReqCtx) {
tn := rc.GinCtx.Query("tableName")
biz.NotEmpty(tn, "tableName不能为空")
rc.ResData = d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx)).GetCreateTableDdl(tn)
}
// @router /api/db/:dbId/exec-sql [get]
func (d *Db) ExecSql(rc *ctx.ReqCtx) {
g := rc.GinCtx
id, db := GetIdAndDb(g)
dbInstance := d.DbApp.GetDbInstance(id, db)
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbInstance.ProjectId), "%s")
// 去除前后空格及换行符
sql := strings.TrimFunc(g.Query("sql"), func(r rune) bool {
s := string(r)
return s == " " || s == "\n"
})
rc.ReqParam = fmt.Sprintf("db: %d:%s | sql: %s", id, db, sql)
biz.NotEmpty(sql, "sql不能为空")
if strings.HasPrefix(sql, "SELECT") || strings.HasPrefix(sql, "select") || strings.HasPrefix(sql, "show") {
colNames, res, err := dbInstance.SelectData(sql)
biz.ErrIsNilAppendErr(err, "查询失败: %s")
colAndRes := make(map[string]interface{})
colAndRes["colNames"] = colNames
colAndRes["res"] = res
rc.ResData = colAndRes
} else {
rowsAffected, err := dbInstance.Exec(sql)
biz.ErrIsNilAppendErr(err, "执行失败: %s")
res := make([]map[string]string, 0)
resData := make(map[string]string)
resData["影响条数"] = fmt.Sprintf("%d", rowsAffected)
res = append(res, resData)
colAndRes := make(map[string]interface{})
colAndRes["colNames"] = []string{"影响条数"}
colAndRes["res"] = res
rc.ResData = colAndRes
}
}
// 执行sql文件
func (d *Db) ExecSqlFile(rc *ctx.ReqCtx) {
g := rc.GinCtx
fileheader, err := g.FormFile("file")
biz.ErrIsNilAppendErr(err, "读取sql文件失败: %s")
// 读取sql文件并根据;切割sql语句
file, _ := fileheader.Open()
filename := fileheader.Filename
bytes, _ := ioutil.ReadAll(file)
sqlContent := string(bytes)
sqls := strings.Split(sqlContent, ";")
dbId, db := GetIdAndDb(g)
go func() {
db := d.DbApp.GetDbInstance(dbId, db)
dbEntity := d.DbApp.GetById(dbId)
dbInfo := fmt.Sprintf("于%s的%s环境", dbEntity.Name, dbEntity.Env)
defer func() {
if err := recover(); err != nil {
switch t := err.(type) {
case *biz.BizError:
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.ErrMsg("sql脚本执行失败", fmt.Sprintf("[%s]%s执行失败: [%s]", filename, dbInfo, t.Error())))
}
}
}()
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, db.ProjectId), "%s")
for _, sql := range sqls {
sql = strings.Trim(sql, " ")
if sql == "" || sql == "\n" {
continue
}
_, err := db.Exec(sql)
if err != nil {
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.ErrMsg("sql脚本执行失败", fmt.Sprintf("[%s]%s执行失败: [%s]", filename, dbInfo, err.Error())))
return
}
}
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.SuccessMsg("sql脚本执行成功", fmt.Sprintf("[%s]%s执行完成", filename, dbInfo)))
}()
}
// @router /api/db/:dbId/t-metadata [get]
func (d *Db) TableMA(rc *ctx.ReqCtx) {
dbi := d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx))
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "%s")
rc.ResData = dbi.GetTableMetedatas()
}
// @router /api/db/:dbId/c-metadata [get]
func (d *Db) ColumnMA(rc *ctx.ReqCtx) {
g := rc.GinCtx
tn := g.Query("tableName")
biz.NotEmpty(tn, "tableName不能为空")
dbi := d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx))
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "%s")
rc.ResData = dbi.GetColumnMetadatas(tn)
}
// @router /api/db/:dbId/hint-tables [get]
func (d *Db) HintTables(rc *ctx.ReqCtx) {
dbi := d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx))
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "%s")
// 获取所有表
tables := dbi.GetTableMetedatas()
tableNames := make([]string, 0)
for _, v := range tables {
tableNames = append(tableNames, v["tableName"])
}
// key = 表名value = 列名数组
res := make(map[string][]string)
// 表为空,则直接返回
if len(tableNames) == 0 {
rc.ResData = res
return
}
// 获取所有表下的所有列信息
columnMds := dbi.GetColumnMetadatas(tableNames...)
for _, v := range columnMds {
tName := v["tableName"]
if res[tName] == nil {
res[tName] = make([]string, 0)
}
columnName := fmt.Sprintf("%s [%s]", v["columnName"], v["columnType"])
comment := v["columnComment"]
// 如果字段备注不为空,则加上备注信息
if comment != "" {
columnName = fmt.Sprintf("%s[%s]", columnName, comment)
}
res[tName] = append(res[tName], columnName)
}
rc.ResData = res
}
// @router /api/db/:dbId/sql [post]
func (d *Db) SaveSql(rc *ctx.ReqCtx) {
g := rc.GinCtx
account := rc.LoginAccount
dbSqlForm := &form.DbSqlSaveForm{}
ginx.BindJsonAndValid(g, dbSqlForm)
rc.ReqParam = dbSqlForm
dbId := GetDbId(g)
// 判断dbId是否存在
err := model.GetById(new(entity.Db), dbId)
biz.ErrIsNil(err, "该数据库信息不存在")
// 获取用于是否有该dbsql的保存记录有则更改否则新增
dbSql := &entity.DbSql{Type: dbSqlForm.Type, DbId: dbId, Name: dbSqlForm.Name, Db: dbSqlForm.Db}
dbSql.CreatorId = account.Id
e := model.GetBy(dbSql)
dbSql.SetBaseInfo(account)
// 更新sql信息
dbSql.Sql = dbSqlForm.Sql
if e == nil {
model.UpdateById(dbSql)
} else {
model.Insert(dbSql)
}
}
// 获取所有保存的sql names
func (d *Db) GetSqlNames(rc *ctx.ReqCtx) {
id, db := GetIdAndDb(rc.GinCtx)
// 获取用于是否有该dbsql的保存记录有则更改否则新增
dbSql := &entity.DbSql{Type: 1, DbId: id, Db: db}
dbSql.CreatorId = rc.LoginAccount.Id
var sqls []entity.DbSql
model.ListBy(dbSql, &sqls, "id", "name")
rc.ResData = sqls
}
// 删除保存的sql
func (d *Db) DeleteSql(rc *ctx.ReqCtx) {
dbSql := &entity.DbSql{Type: 1, DbId: GetDbId(rc.GinCtx)}
dbSql.CreatorId = rc.LoginAccount.Id
dbSql.Name = rc.GinCtx.Query("name")
model.DeleteByCondition(dbSql)
}
// @router /api/db/:dbId/sql [get]
func (d *Db) GetSql(rc *ctx.ReqCtx) {
id, db := GetIdAndDb(rc.GinCtx)
// 根据创建者id 数据库id以及sql模板名称查询保存的sql信息
dbSql := &entity.DbSql{Type: 1, DbId: id, Db: db}
dbSql.CreatorId = rc.LoginAccount.Id
dbSql.Name = rc.GinCtx.Query("name")
e := model.GetBy(dbSql)
if e != nil {
return
}
rc.ResData = dbSql
}
func GetDbId(g *gin.Context) uint64 {
dbId, _ := strconv.Atoi(g.Param("dbId"))
biz.IsTrue(dbId > 0, "dbId错误")
return uint64(dbId)
}
func GetIdAndDb(g *gin.Context) (uint64, string) {
db := g.Query("db")
biz.NotEmpty(db, "db不能为空")
return GetDbId(g), db
}

View File

@@ -0,0 +1,16 @@
package form
type DbForm struct {
Id uint64
Name string `binding:"required" json:"name"`
Type string `binding:"required" json:"type"` // 类型mysql oracle等
Host string `binding:"required" json:"host"`
Port int `binding:"required" json:"port"`
Username string `binding:"required" json:"username"`
Password string `json:"password"`
Database string `binding:"required" json:"database"`
ProjectId uint64 `binding:"required" json:"projectId"`
Project string `json:"project"`
Env string `json:"env"`
EnvId uint64 `binding:"required" json:"envId"`
}

View File

@@ -0,0 +1,52 @@
package form
type MachineForm struct {
Id uint64 `json:"id"`
ProjectId uint64 `json:"projectId"`
ProjectName string `json:"projectName"`
Name string `json:"name" binding:"required"`
// IP地址
Ip string `json:"ip" binding:"required"`
// 用户名
Username string `json:"username" binding:"required"`
Password string `json:"password"`
// 端口号
Port int `json:"port" binding:"required"`
Remark string `json:"remark"`
}
type MachineRunForm struct {
MachineId int64 `binding:"required"`
Cmd string `binding:"required"`
}
type MachineFileForm struct {
Id uint64
Name string `binding:"required"`
MachineId uint64 `binding:"required"`
Type int `binding:"required"`
Path string `binding:"required"`
}
type MachineScriptForm struct {
Id uint64
Name string `binding:"required"`
MachineId uint64 `binding:"required"`
Type int `binding:"required"`
Description string `binding:"required"`
Params string
Script string `binding:"required"`
}
type DbSqlSaveForm struct {
Name string
Sql string `binding:"required"`
Type int `binding:"required"`
Db string `binding:"required"`
}
type MachineFileUpdateForm struct {
Content string `binding:"required"`
Id uint64 `binding:"required"`
Path string `binding:"required"`
}

View File

@@ -0,0 +1,40 @@
package form
type Mongo struct {
Id uint64
Uri string `binding:"required" json:"uri"`
Name string `binding:"required" json:"name"`
ProjectId uint64 `binding:"required" json:"projectId"`
Project string `json:"project"`
Env string `json:"env"`
EnvId uint64 `binding:"required" json:"envId"`
}
type MongoCommand struct {
Database string `binding:"required" json:"database"`
Collection string `binding:"required" json:"collection"`
Filter map[string]interface{} `json:"filter"`
}
type MongoRunCommand struct {
Database string `binding:"required" json:"database"`
Command map[string]interface{} `json:"command"`
}
type MongoFindCommand struct {
MongoCommand
Sort map[string]interface{} `json:"sort"`
Skip int64
Limit int64
}
type MongoUpdateByIdCommand struct {
MongoCommand
DocId interface{} `binding:"required" json:"docId"`
Update map[string]interface{} `json:"update"`
}
type MongoInsertCommand struct {
MongoCommand
Doc map[string]interface{} `json:"doc"`
}

View File

@@ -0,0 +1,32 @@
package form
type Redis struct {
Id uint64
Host string `binding:"required" json:"host"`
Password string `json:"password"`
Db int `json:"db"`
ProjectId uint64 `binding:"required" json:"projectId"`
Project string `json:"project"`
Env string `json:"env"`
EnvId uint64 `binding:"required" json:"envId"`
}
type KeyInfo struct {
Key string `binding:"required" json:"key"`
Timed int64
}
type StringValue struct {
KeyInfo
Value interface{} `binding:"required" json:"value"`
}
type HashValue struct {
KeyInfo
Value []map[string]interface{} `binding:"required" json:"value"`
}
type SetValue struct {
KeyInfo
Value []interface{} `binding:"required" json:"value"`
}

View File

@@ -0,0 +1,165 @@
package api
import (
"fmt"
"mayfly-go/internal/devops/api/form"
"mayfly-go/internal/devops/api/vo"
"mayfly-go/internal/devops/application"
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/internal/devops/infrastructure/machine"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/ctx"
"mayfly-go/pkg/ginx"
"mayfly-go/pkg/utils"
"mayfly-go/pkg/ws"
"strconv"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
)
type Machine struct {
MachineApp application.Machine
ProjectApp application.Project
}
func (m *Machine) Machines(rc *ctx.ReqCtx) {
condition := new(entity.Machine)
// 使用创建者id模拟账号成员id
condition.CreatorId = rc.LoginAccount.Id
condition.Ip = rc.GinCtx.Query("ip")
condition.Name = rc.GinCtx.Query("name")
condition.ProjectId = uint64(ginx.QueryInt(rc.GinCtx, "projectId", 0))
res := m.MachineApp.GetMachineList(condition, ginx.GetPageParam(rc.GinCtx), new([]*vo.MachineVO))
if res.Total == 0 {
rc.ResData = res
return
}
list := res.List.(*[]*vo.MachineVO)
for _, mv := range *list {
mv.HasCli = machine.HasCli(*mv.Id)
}
rc.ResData = res
}
func (m *Machine) MachineStats(rc *ctx.ReqCtx) {
stats := m.MachineApp.GetCli(GetMachineId(rc.GinCtx)).GetAllStats()
rc.ResData = stats
}
func (m *Machine) SaveMachine(rc *ctx.ReqCtx) {
g := rc.GinCtx
machineForm := new(form.MachineForm)
ginx.BindJsonAndValid(g, machineForm)
entity := new(entity.Machine)
utils.Copy(entity, machineForm)
entity.SetBaseInfo(rc.LoginAccount)
m.MachineApp.Save(entity)
}
func (m *Machine) ChangeStatus(rc *ctx.ReqCtx) {
g := rc.GinCtx
id := uint64(ginx.PathParamInt(g, "machineId"))
status := int8(ginx.PathParamInt(g, "status"))
rc.ReqParam = fmt.Sprintf("id: %d -- status: %d", id, status)
m.MachineApp.ChangeStatus(id, status)
}
func (m *Machine) DeleteMachine(rc *ctx.ReqCtx) {
id := uint64(ginx.PathParamInt(rc.GinCtx, "machineId"))
rc.ReqParam = id
m.MachineApp.Delete(id)
}
// 关闭机器客户端
func (m *Machine) CloseCli(rc *ctx.ReqCtx) {
machine.DeleteCli(GetMachineId(rc.GinCtx))
}
// 获取进程列表信息
func (m *Machine) GetProcess(rc *ctx.ReqCtx) {
g := rc.GinCtx
cmd := "ps -aux "
sortType := g.Query("sortType")
if sortType == "2" {
cmd += "--sort -pmem "
} else {
cmd += "--sort -pcpu "
}
pname := g.Query("name")
if pname != "" {
cmd += fmt.Sprintf("| grep %s ", pname)
}
count := g.Query("count")
if count == "" {
count = "10"
}
cmd += "| head -n " + count
cli := m.MachineApp.GetCli(GetMachineId(rc.GinCtx))
biz.ErrIsNilAppendErr(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "%s")
res, err := cli.Run(cmd)
biz.ErrIsNilAppendErr(err, "获取进程信息失败: %s")
rc.ResData = res
}
// 终止进程
func (m *Machine) KillProcess(rc *ctx.ReqCtx) {
pid := rc.GinCtx.Query("pid")
biz.NotEmpty(pid, "进程id不能为空")
cli := m.MachineApp.GetCli(GetMachineId(rc.GinCtx))
biz.ErrIsNilAppendErr(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "%s")
_, err := cli.Run("kill -9 " + pid)
biz.ErrIsNilAppendErr(err, "终止进程失败: %s")
}
func (m *Machine) WsSSH(g *gin.Context) {
wsConn, err := ws.Upgrader.Upgrade(g.Writer, g.Request, nil)
defer func() {
if err := recover(); err != nil {
wsConn.WriteMessage(websocket.TextMessage, []byte(err.(error).Error()))
wsConn.Close()
}
}()
if err != nil {
panic(biz.NewBizErr("升级websocket失败"))
}
// 权限校验
rc := ctx.NewReqCtxWithGin(g).WithRequiredPermission(ctx.NewPermission("machine:terminal"))
if err = ctx.PermissionHandler(rc); err != nil {
panic(biz.NewBizErr("没有权限"))
}
cols := ginx.QueryInt(g, "cols", 80)
rows := ginx.QueryInt(g, "rows", 40)
cli := m.MachineApp.GetCli(GetMachineId(g))
biz.ErrIsNilAppendErr(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "%s")
sws, err := machine.NewLogicSshWsSession(cols, rows, cli, wsConn)
biz.ErrIsNilAppendErr(err, "连接失败:%s")
defer sws.Close()
quitChan := make(chan bool, 3)
sws.Start(quitChan)
go sws.Wait(quitChan)
<-quitChan
}
func GetMachineId(g *gin.Context) uint64 {
machineId, _ := strconv.Atoi(g.Param("machineId"))
biz.IsTrue(machineId != 0, "machineId错误")
return uint64(machineId)
}

View File

@@ -0,0 +1,177 @@
package api
import (
"fmt"
"io/fs"
"io/ioutil"
"mayfly-go/internal/devops/api/form"
"mayfly-go/internal/devops/api/vo"
"mayfly-go/internal/devops/application"
"mayfly-go/internal/devops/domain/entity"
sysApplication "mayfly-go/internal/sys/application"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/ctx"
"mayfly-go/pkg/ginx"
"mayfly-go/pkg/utils"
"mayfly-go/pkg/ws"
"strconv"
"strings"
"github.com/gin-gonic/gin"
)
type MachineFile struct {
MachineFileApp application.MachineFile
MachineApp application.Machine
MsgApp sysApplication.Msg
}
const (
file = "-"
dir = "d"
link = "l"
max_read_size = 1 * 1024 * 1024
)
func (m *MachineFile) MachineFiles(rc *ctx.ReqCtx) {
g := rc.GinCtx
condition := &entity.MachineFile{MachineId: GetMachineId(g)}
rc.ResData = m.MachineFileApp.GetPageList(condition, ginx.GetPageParam(g), new([]vo.MachineFileVO))
}
func (m *MachineFile) SaveMachineFiles(rc *ctx.ReqCtx) {
g := rc.GinCtx
fileForm := new(form.MachineFileForm)
ginx.BindJsonAndValid(g, fileForm)
entity := new(entity.MachineFile)
utils.Copy(entity, fileForm)
entity.SetBaseInfo(rc.LoginAccount)
m.MachineFileApp.Save(entity)
}
func (m *MachineFile) DeleteFile(rc *ctx.ReqCtx) {
g := rc.GinCtx
fid := GetMachineFileId(g)
m.MachineFileApp.Delete(fid)
}
/*** sftp相关操作 */
func (m *MachineFile) ReadFileContent(rc *ctx.ReqCtx) {
g := rc.GinCtx
fid := GetMachineFileId(g)
readPath := g.Query("path")
readType := g.Query("type")
sftpFile := m.MachineFileApp.ReadFile(fid, readPath)
defer sftpFile.Close()
fileInfo, _ := sftpFile.Stat()
// 如果是读取文件内容,则校验文件大小
if readType != "1" {
biz.IsTrue(fileInfo.Size() < max_read_size, "文件超过1m请使用下载查看")
}
rc.ReqParam = fmt.Sprintf("path: %s", readPath)
// 如果读取类型为下载,则下载文件,否则获取文件内容
if readType == "1" {
// 截取文件名,如/usr/local/test.java -》 test.java
path := strings.Split(readPath, "/")
rc.Download(sftpFile, path[len(path)-1])
} else {
datas, err := ioutil.ReadAll(sftpFile)
biz.ErrIsNilAppendErr(err, "读取文件内容失败: %s")
rc.ResData = string(datas)
}
}
func (m *MachineFile) GetDirEntry(rc *ctx.ReqCtx) {
g := rc.GinCtx
fid := GetMachineFileId(g)
readPath := g.Query("path")
if !strings.HasSuffix(readPath, "/") {
readPath = readPath + "/"
}
fis := m.MachineFileApp.ReadDir(fid, readPath)
fisVO := make([]vo.MachineFileInfo, 0)
for _, fi := range fis {
fisVO = append(fisVO, vo.MachineFileInfo{
Name: fi.Name(),
Size: fi.Size(),
Path: readPath + fi.Name(),
Type: getFileType(fi.Mode()),
})
}
rc.ResData = fisVO
rc.ReqParam = fmt.Sprintf("path: %s", readPath)
}
func (m *MachineFile) WriteFileContent(rc *ctx.ReqCtx) {
g := rc.GinCtx
fid := GetMachineFileId(g)
form := new(form.MachineFileUpdateForm)
ginx.BindJsonAndValid(g, form)
path := form.Path
m.MachineFileApp.WriteFileContent(fid, path, []byte(form.Content))
rc.ReqParam = fmt.Sprintf("path: %s", path)
}
func (m *MachineFile) UploadFile(rc *ctx.ReqCtx) {
g := rc.GinCtx
fid := GetMachineFileId(g)
path := g.PostForm("path")
fileheader, err := g.FormFile("file")
biz.ErrIsNilAppendErr(err, "读取文件失败: %s")
file, _ := fileheader.Open()
rc.ReqParam = fmt.Sprintf("path: %s", path)
la := rc.LoginAccount
go func() {
defer func() {
if err := recover(); err != nil {
switch t := err.(type) {
case *biz.BizError:
m.MsgApp.CreateAndSend(la, ws.ErrMsg("文件上传失败", fmt.Sprintf("执行文件上传失败:\n<-e errCode: %d, errMsg: %s", t.Code(), t.Error())))
}
}
}()
defer file.Close()
m.MachineFileApp.UploadFile(fid, path, fileheader.Filename, file)
// 保存消息并发送文件上传成功通知
machine := m.MachineApp.GetById(m.MachineFileApp.GetById(fid).MachineId)
m.MsgApp.CreateAndSend(la, ws.SuccessMsg("文件上传成功", fmt.Sprintf("[%s]文件已成功上传至 %s[%s:%s]", fileheader.Filename, machine.Name, machine.Ip, path)))
}()
}
func (m *MachineFile) RemoveFile(rc *ctx.ReqCtx) {
g := rc.GinCtx
fid := GetMachineFileId(g)
// mid := GetMachineId(g)
path := g.Query("path")
m.MachineFileApp.RemoveFile(fid, path)
rc.ReqParam = fmt.Sprintf("path: %s", path)
}
func getFileType(fm fs.FileMode) string {
if fm.IsDir() {
return dir
}
return file
}
func GetMachineFileId(g *gin.Context) uint64 {
fileId, _ := strconv.Atoi(g.Param("fileId"))
biz.IsTrue(fileId != 0, "fileId错误")
return uint64(fileId)
}

View File

@@ -0,0 +1,82 @@
package api
import (
"fmt"
"mayfly-go/internal/devops/api/form"
"mayfly-go/internal/devops/api/vo"
"mayfly-go/internal/devops/application"
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/ctx"
"mayfly-go/pkg/ginx"
"mayfly-go/pkg/utils"
"strconv"
"github.com/gin-gonic/gin"
)
type MachineScript struct {
MachineScriptApp application.MachineScript
MachineApp application.Machine
ProjectApp application.Project
}
func (m *MachineScript) MachineScripts(rc *ctx.ReqCtx) {
g := rc.GinCtx
condition := &entity.MachineScript{MachineId: GetMachineId(g)}
rc.ResData = m.MachineScriptApp.GetPageList(condition, ginx.GetPageParam(g), new([]vo.MachineScriptVO))
}
func (m *MachineScript) SaveMachineScript(rc *ctx.ReqCtx) {
form := new(form.MachineScriptForm)
ginx.BindJsonAndValid(rc.GinCtx, form)
rc.ReqParam = form
// 转换为entity并设置基本信息
machineScript := new(entity.MachineScript)
utils.Copy(machineScript, form)
machineScript.SetBaseInfo(rc.LoginAccount)
m.MachineScriptApp.Save(machineScript)
}
func (m *MachineScript) DeleteMachineScript(rc *ctx.ReqCtx) {
msa := m.MachineScriptApp
sid := GetMachineScriptId(rc.GinCtx)
ms := msa.GetById(sid)
biz.NotNil(ms, "该脚本不存在")
rc.ReqParam = fmt.Sprintf("[scriptId: %d, name: %s, desc: %s, script: %s]", sid, ms.Name, ms.Description, ms.Script)
msa.Delete(sid)
}
func (m *MachineScript) RunMachineScript(rc *ctx.ReqCtx) {
g := rc.GinCtx
scriptId := GetMachineScriptId(g)
machineId := GetMachineId(g)
ms := m.MachineScriptApp.GetById(scriptId, "MachineId", "Name", "Script")
biz.NotNil(ms, "该脚本不存在")
biz.IsTrue(ms.MachineId == application.Common_Script_Machine_Id || ms.MachineId == machineId, "该脚本不属于该机器")
script := ms.Script
// 如果有脚本参数,则用脚本参数替换脚本中的模板占位符参数
if params := g.Query("params"); params != "" {
script = utils.TemplateParse(ms.Script, utils.Json2Map(params))
}
cli := m.MachineApp.GetCli(machineId)
biz.ErrIsNilAppendErr(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "%s")
res, err := cli.Run(script)
// 记录请求参数
rc.ReqParam = fmt.Sprintf("[machineId: %d, scriptId: %d, name: %s]", machineId, scriptId, ms.Name)
if err != nil {
panic(biz.NewBizErr(fmt.Sprintf("执行命令失败:%s", err.Error())))
}
rc.ResData = res
}
func GetMachineScriptId(g *gin.Context) uint64 {
scriptId, _ := strconv.Atoi(g.Param("scriptId"))
biz.IsTrue(scriptId > 0, "scriptId错误")
return uint64(scriptId)
}

View File

@@ -0,0 +1,168 @@
package api
import (
"context"
"mayfly-go/internal/devops/api/form"
"mayfly-go/internal/devops/application"
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/ctx"
"mayfly-go/pkg/ginx"
"mayfly-go/pkg/utils"
"strconv"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
type Mongo struct {
MongoApp application.Mongo
}
func (m *Mongo) Mongos(rc *ctx.ReqCtx) {
g := rc.GinCtx
mc := &entity.Mongo{EnvId: uint64(ginx.QueryInt(g, "envId", 0)),
ProjectId: uint64(ginx.QueryInt(g, "projectId", 0)),
}
mc.CreatorId = rc.LoginAccount.Id
rc.ResData = m.MongoApp.GetPageList(mc, ginx.GetPageParam(rc.GinCtx), new([]entity.Mongo))
}
func (m *Mongo) Save(rc *ctx.ReqCtx) {
form := &form.Mongo{}
ginx.BindJsonAndValid(rc.GinCtx, form)
rc.ReqParam = form
mongo := new(entity.Mongo)
utils.Copy(mongo, form)
mongo.SetBaseInfo(rc.LoginAccount)
m.MongoApp.Save(mongo)
}
func (m *Mongo) DeleteMongo(rc *ctx.ReqCtx) {
m.MongoApp.Delete(m.GetMongoId(rc.GinCtx))
}
func (m *Mongo) Databases(rc *ctx.ReqCtx) {
cli := m.MongoApp.GetMongoCli(m.GetMongoId(rc.GinCtx))
res, err := cli.ListDatabases(context.TODO(), bson.D{})
biz.ErrIsNilAppendErr(err, "获取mongo所有库信息失败: %s")
rc.ResData = res
}
func (m *Mongo) Collections(rc *ctx.ReqCtx) {
cli := m.MongoApp.GetMongoCli(m.GetMongoId(rc.GinCtx))
db := rc.GinCtx.Query("database")
biz.NotEmpty(db, "database不能为空")
ctx := context.TODO()
res, err := cli.Database(db).ListCollectionNames(ctx, bson.D{})
biz.ErrIsNilAppendErr(err, "获取库集合信息失败: %s")
rc.ResData = res
}
func (m *Mongo) RunCommand(rc *ctx.ReqCtx) {
commandForm := new(form.MongoRunCommand)
ginx.BindJsonAndValid(rc.GinCtx, commandForm)
cli := m.MongoApp.GetMongoCli(m.GetMongoId(rc.GinCtx))
ctx := context.TODO()
var bm bson.M
err := cli.Database(commandForm.Database).RunCommand(
ctx,
commandForm.Command,
).Decode(&bm)
biz.ErrIsNilAppendErr(err, "执行命令失败: %s")
rc.ResData = bm
}
func (m *Mongo) FindCommand(rc *ctx.ReqCtx) {
g := rc.GinCtx
cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
commandForm := new(form.MongoFindCommand)
ginx.BindJsonAndValid(g, commandForm)
limit := commandForm.Limit
if limit != 0 {
biz.IsTrue(limit <= 100, "limit不能超过100")
}
opts := options.Find().SetSort(commandForm.Sort).
SetSkip(commandForm.Skip).
SetLimit(limit)
ctx := context.TODO()
cur, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).Find(ctx, commandForm.Filter, opts)
biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
var res []bson.M
cur.All(ctx, &res)
rc.ResData = res
}
func (m *Mongo) UpdateByIdCommand(rc *ctx.ReqCtx) {
g := rc.GinCtx
cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
commandForm := new(form.MongoUpdateByIdCommand)
ginx.BindJsonAndValid(g, commandForm)
// 解析docId文档id如果为string类型则使用ObjectId解析解析失败则为普通字符串
docId := commandForm.DocId
docIdVal, ok := docId.(string)
if ok {
objId, err := primitive.ObjectIDFromHex(docIdVal)
if err == nil {
docId = objId
}
}
res, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).UpdateByID(context.TODO(), docId, commandForm.Update)
biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
rc.ReqParam = commandForm
rc.ResData = res
}
func (m *Mongo) DeleteByIdCommand(rc *ctx.ReqCtx) {
g := rc.GinCtx
cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
commandForm := new(form.MongoUpdateByIdCommand)
ginx.BindJsonAndValid(g, commandForm)
// 解析docId文档id如果为string类型则使用ObjectId解析解析失败则为普通字符串
docId := commandForm.DocId
docIdVal, ok := docId.(string)
if ok {
objId, err := primitive.ObjectIDFromHex(docIdVal)
if err == nil {
docId = objId
}
}
res, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).DeleteOne(context.TODO(), bson.D{{"_id", docId}})
biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
rc.ReqParam = commandForm
rc.ResData = res
}
func (m *Mongo) InsertOneCommand(rc *ctx.ReqCtx) {
g := rc.GinCtx
cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
commandForm := new(form.MongoInsertCommand)
ginx.BindJsonAndValid(g, commandForm)
res, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).InsertOne(context.TODO(), commandForm.Doc)
biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
rc.ReqParam = commandForm
rc.ResData = res
}
// 获取请求路径上的mongo id
func (m *Mongo) GetMongoId(g *gin.Context) uint64 {
dbId, _ := strconv.Atoi(g.Param("id"))
biz.IsTrue(dbId > 0, "mongoId错误")
return uint64(dbId)
}

View File

@@ -0,0 +1,104 @@
package api
import (
"fmt"
"mayfly-go/internal/devops/api/vo"
"mayfly-go/internal/devops/application"
"mayfly-go/internal/devops/domain/entity"
sys_applicaiton "mayfly-go/internal/sys/application"
sys_entity "mayfly-go/internal/sys/domain/entity"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/ctx"
"mayfly-go/pkg/ginx"
)
type Project struct {
ProjectApp application.Project
AccountApp sys_applicaiton.Account
}
// 获取当前登录用户可以访问的项目列表
func (p *Project) GetProjectsByLoginAccount(rc *ctx.ReqCtx) {
// 获取登录用户拥有的项目ids
projectMembers := &[]entity.ProjectMember{}
p.ProjectApp.ListMember(&entity.ProjectMember{AccountId: rc.LoginAccount.Id}, projectMembers)
var pids []uint64
for _, pm := range *projectMembers {
pids = append(pids, pm.ProjectId)
}
// 获取项目信息
projects := &vo.AccountProjects{}
p.ProjectApp.ListProjectByIds(pids, projects)
rc.ResData = projects
}
func (p *Project) GetProjects(rc *ctx.ReqCtx) {
condition := &entity.Project{}
ginx.BindQuery(rc.GinCtx, condition)
// condition.Name = rc.GinCtx.Query("name")
rc.ResData = p.ProjectApp.GetPageList(condition, ginx.GetPageParam(rc.GinCtx), new([]entity.Project))
}
func (p *Project) SaveProject(rc *ctx.ReqCtx) {
project := &entity.Project{}
ginx.BindJsonAndValid(rc.GinCtx, project)
rc.ReqParam = project
project.SetBaseInfo(rc.LoginAccount)
p.ProjectApp.SaveProject(project)
}
func (p *Project) DelProject(rc *ctx.ReqCtx) {
p.ProjectApp.DelProject(uint64(ginx.QueryInt(rc.GinCtx, "id", 0)))
}
// 获取项目下的环境信息
func (p *Project) GetProjectEnvs(rc *ctx.ReqCtx) {
projectEnvs := &[]entity.ProjectEnv{}
p.ProjectApp.ListEnvByProjectId(uint64(ginx.PathParamInt(rc.GinCtx, "projectId")), projectEnvs)
rc.ResData = projectEnvs
}
//保存项目下的环境信息
func (p *Project) SaveProjectEnvs(rc *ctx.ReqCtx) {
projectEnv := &entity.ProjectEnv{}
ginx.BindJsonAndValid(rc.GinCtx, projectEnv)
rc.ReqParam = projectEnv
projectEnv.SetBaseInfo(rc.LoginAccount)
p.ProjectApp.SaveProjectEnv(projectEnv)
}
// 获取项目下的成员信息
func (p *Project) GetProjectMembers(rc *ctx.ReqCtx) {
projectMems := &[]entity.ProjectMember{}
rc.ResData = p.ProjectApp.GetMemberPage(&entity.ProjectMember{ProjectId: uint64(ginx.PathParamInt(rc.GinCtx, "projectId"))},
ginx.GetPageParam(rc.GinCtx), projectMems)
}
//保存项目的成员信息
func (p *Project) SaveProjectMember(rc *ctx.ReqCtx) {
projectMem := &entity.ProjectMember{}
ginx.BindJsonAndValid(rc.GinCtx, projectMem)
rc.ReqParam = projectMem
// 校验账号并赋值username
account := &sys_entity.Account{}
account.Id = projectMem.AccountId
biz.ErrIsNil(p.AccountApp.GetAccount(account, "Id", "Username"), "账号不存在")
projectMem.Username = account.Username
projectMem.SetBaseInfo(rc.LoginAccount)
p.ProjectApp.SaveProjectMember(projectMem)
}
//删除项目成员
func (p *Project) DelProjectMember(rc *ctx.ReqCtx) {
g := rc.GinCtx
pid := ginx.PathParamInt(g, "projectId")
aid := ginx.PathParamInt(g, "accountId")
rc.ReqParam = fmt.Sprintf("projectId: %d, accountId: %d", pid, aid)
p.ProjectApp.DeleteMember(uint64(pid), uint64(aid))
}

View File

@@ -0,0 +1,216 @@
package api
import (
"mayfly-go/internal/devops/api/form"
"mayfly-go/internal/devops/api/vo"
"mayfly-go/internal/devops/application"
"mayfly-go/internal/devops/domain/entity"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/ctx"
"mayfly-go/pkg/ginx"
"mayfly-go/pkg/utils"
"strconv"
"strings"
"time"
)
type Redis struct {
RedisApp application.Redis
ProjectApp application.Project
}
func (r *Redis) RedisList(rc *ctx.ReqCtx) {
g := rc.GinCtx
m := &entity.Redis{EnvId: uint64(ginx.QueryInt(g, "envId", 0)),
ProjectId: uint64(ginx.QueryInt(g, "projectId", 0)),
}
m.CreatorId = rc.LoginAccount.Id
rc.ResData = r.RedisApp.GetPageList(m, ginx.GetPageParam(rc.GinCtx), new([]vo.Redis))
}
func (r *Redis) Save(rc *ctx.ReqCtx) {
form := &form.Redis{}
ginx.BindJsonAndValid(rc.GinCtx, form)
rc.ReqParam = form
redis := new(entity.Redis)
utils.Copy(redis, form)
redis.SetBaseInfo(rc.LoginAccount)
r.RedisApp.Save(redis)
}
func (r *Redis) DeleteRedis(rc *ctx.ReqCtx) {
r.RedisApp.Delete(uint64(ginx.PathParamInt(rc.GinCtx, "id")))
}
func (r *Redis) RedisInfo(rc *ctx.ReqCtx) {
res, _ := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(rc.GinCtx, "id"))).Cli.Info().Result()
datas := strings.Split(res, "\r\n")
i := 0
length := len(datas)
parseMap := make(map[string]map[string]string)
for {
if i >= length {
break
}
if strings.Contains(datas[i], "#") {
key := utils.SubString(datas[i], strings.Index(datas[i], "#")+1, utils.StrLen(datas[i]))
i++
key = strings.Trim(key, " ")
sectionMap := make(map[string]string)
for {
if i >= length || !strings.Contains(datas[i], ":") {
break
}
pair := strings.Split(datas[i], ":")
i++
if len(pair) != 2 {
continue
}
sectionMap[pair[0]] = pair[1]
}
parseMap[key] = sectionMap
} else {
i++
}
}
rc.ResData = parseMap
}
// scan获取redis的key列表信息
func (r *Redis) Scan(rc *ctx.ReqCtx) {
g := rc.GinCtx
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
keys, cursor := ri.Scan(uint64(ginx.PathParamInt(g, "cursor")), g.Query("match"), int64(ginx.PathParamInt(g, "count")))
var keyInfoSplit []string
if len(keys) > 0 {
keyInfoLua := `
local result = {}
-- KEYS[1]为第1个参数lua数组下标从1开始
local ttl = redis.call('ttl', KEYS[1]);
local keyType = redis.call('type', KEYS[1]);
for i = 1, #KEYS do
local ttl = redis.call('ttl', KEYS[i]);
local keyType = redis.call('type', KEYS[i]);
table.insert(result, string.format("%d,%s", ttl, keyType['ok']));
end;
return table.concat(result, ".");`
// 通过lua获取 ttl,type.ttl2,type2格式以便下面切割获取ttl和type。避免多次调用ttl和type函数
keyInfos, _ := ri.Cli.Eval(keyInfoLua, keys).Result()
keyInfoSplit = strings.Split(keyInfos.(string), ".")
}
kis := make([]*vo.KeyInfo, 0)
for i, k := range keys {
ttlType := strings.Split(keyInfoSplit[i], ",")
ttl, _ := strconv.Atoi(ttlType[0])
ki := &vo.KeyInfo{Key: k, Type: ttlType[1], Ttl: int64(ttl)}
kis = append(kis, ki)
}
size, _ := ri.Cli.DBSize().Result()
rc.ResData = &vo.Keys{Cursor: cursor, Keys: kis, DbSize: size}
}
func (r *Redis) DeleteKey(rc *ctx.ReqCtx) {
g := rc.GinCtx
key := g.Query("key")
biz.NotEmpty(key, "key不能为空")
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
rc.ReqParam = key
ri.Cli.Del(key)
}
func (r *Redis) checkKey(rc *ctx.ReqCtx) (*application.RedisInstance, string) {
g := rc.GinCtx
key := g.Query("key")
biz.NotEmpty(key, "key不能为空")
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
return ri, key
}
func (r *Redis) GetStringValue(rc *ctx.ReqCtx) {
ri, key := r.checkKey(rc)
str, err := ri.Cli.Get(key).Result()
biz.ErrIsNilAppendErr(err, "获取字符串值失败: %s")
rc.ResData = str
}
func (r *Redis) GetHashValue(rc *ctx.ReqCtx) {
ri, key := r.checkKey(rc)
res, err := ri.Cli.HGetAll(key).Result()
biz.ErrIsNilAppendErr(err, "获取hash值失败: %s")
rc.ResData = res
}
func (r *Redis) SetStringValue(rc *ctx.ReqCtx) {
g := rc.GinCtx
keyValue := new(form.StringValue)
ginx.BindJsonAndValid(g, keyValue)
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
str, err := ri.Cli.Set(keyValue.Key, keyValue.Value, time.Second*time.Duration(keyValue.Timed)).Result()
biz.ErrIsNilAppendErr(err, "保存字符串值失败: %s")
rc.ResData = str
}
func (r *Redis) SetHashValue(rc *ctx.ReqCtx) {
g := rc.GinCtx
hashValue := new(form.HashValue)
ginx.BindJsonAndValid(g, hashValue)
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
key := hashValue.Key
// 简单处理->先删除,后新增
ri.Cli.Del(key)
for _, v := range hashValue.Value {
res := ri.Cli.HSet(key, v["key"].(string), v["value"])
biz.ErrIsNilAppendErr(res.Err(), "保存hash值失败: %s")
}
if hashValue.Timed != -1 {
ri.Cli.Expire(key, time.Second*time.Duration(hashValue.Timed))
}
}
func (r *Redis) GetSetValue(rc *ctx.ReqCtx) {
ri, key := r.checkKey(rc)
res, err := ri.Cli.SMembers(key).Result()
biz.ErrIsNilAppendErr(err, "获取set值失败: %s")
rc.ResData = res
}
func (r *Redis) SetSetValue(rc *ctx.ReqCtx) {
g := rc.GinCtx
keyvalue := new(form.SetValue)
ginx.BindJsonAndValid(g, keyvalue)
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
key := keyvalue.Key
// 简单处理->先删除,后新增
ri.Cli.Del(key)
ri.Cli.SAdd(key, keyvalue.Value...)
if keyvalue.Timed != -1 {
ri.Cli.Expire(key, time.Second*time.Duration(keyvalue.Timed))
}
}

View File

@@ -0,0 +1,21 @@
package vo
import "time"
type SelectDataDbVO struct {
//models.BaseModel
Id *int64 `json:"id"`
Name *string `json:"name"`
Host *string `json:"host"`
Port *int `json:"port"`
Type *string `json:"type"`
Database *string `json:"database"`
Username *string `json:"username"`
ProjectId *int64 `json:"projectId"`
Project *string `json:"project"`
Env *string `json:"env"`
EnvId *int64 `json:"envId"`
CreateTime *time.Time `json:"createTime"`
Creator *string `json:"creator"`
CreatorId *int64 `json:"creatorId"`
}

View File

@@ -0,0 +1,10 @@
package vo
// 用户选择项目
type AccountProject struct {
Id uint64 `json:"id"`
Name string `json:"name"`
Remark string `json:"remark"`
}
type AccountProjects []AccountProject

View File

@@ -0,0 +1,29 @@
package vo
import "time"
type Redis struct {
Id *int64 `json:"id"`
// Name *string `json:"name"`
Host *string `json:"host"`
Db int `json:"db"`
ProjectId *int64 `json:"projectId"`
Project *string `json:"project"`
Env *string `json:"env"`
EnvId *int64 `json:"envId"`
CreateTime *time.Time `json:"createTime"`
Creator *string `json:"creator"`
CreatorId *int64 `json:"creatorId"`
}
type Keys struct {
Cursor uint64 `json:"cursor"`
Keys []*KeyInfo `json:"keys"`
DbSize int64 `json:"dbSize"`
}
type KeyInfo struct {
Key string `json:"key"`
Ttl int64 `json:"ttl"`
Type string `json:"type"`
}

View File

@@ -0,0 +1,64 @@
package vo
import "time"
type AccountVO struct {
//models.BaseModel
Id *int64 `json:"id"`
Username *string `json:"username"`
CreateTime *string `json:"createTime"`
Creator *string `json:"creator"`
CreatorId *int64 `json:"creatorId"`
// Role *RoleVO `json:"roles"`
//Status int8 `json:"status"`
}
type MachineVO struct {
//models.BaseModel
Id *uint64 `json:"id"`
ProjectId uint64 `json:"projectId"`
ProjectName string `json:"projectName"`
Name *string `json:"name"`
Username *string `json:"username"`
Ip *string `json:"ip"`
Port *int `json:"port"`
Status *int8 `json:"status"`
CreateTime *time.Time `json:"createTime"`
Creator *string `json:"creator"`
CreatorId *int64 `json:"creatorId"`
UpdateTime *time.Time `json:"updateTime"`
Modifier *string `json:"modifier"`
ModifierId *int64 `json:"modifierId"`
HasCli bool `json:"hasCli" gorm:"-"`
Remark *string `json:"remark"`
}
type MachineScriptVO struct {
Id *int64 `json:"id"`
Name *string `json:"name"`
Script *string `json:"script"`
Type *int `json:"type"`
Description *string `json:"description"`
Params *string `json:"params"`
MachineId *uint64 `json:"machineId"`
}
type MachineFileVO struct {
Id *int64 `json:"id"`
Name *string `json:"name"`
Path *string `json:"path"`
Type *int `json:"type"`
MachineId *uint64 `json:"machineId"`
}
type MachineFileInfo struct {
Name string `json:"name"`
Path string `json:"path"`
Size int64 `json:"size"`
Type string `json:"type"`
}
type RoleVO struct {
Id *int64
Name *string
}