feat: 机器定时删除终端操作记录

This commit is contained in:
meilin.huang
2024-01-15 20:51:41 +08:00
parent c0232c4c75
commit 493925064c
15 changed files with 98 additions and 35 deletions

View File

@@ -22,7 +22,7 @@
### 介绍
web 版 **linux(终端[终端回放] 文件 脚本 进程 计划任务)、数据库mysql postgres 达梦、redis(单机 哨兵 集群)、mongo 统一管理操作平台**
web 版 **linux(终端[终端回放] 文件 脚本 进程 计划任务)、数据库mysql postgres oracle 达梦 高斯、redis(单机 哨兵 集群)、mongo 统一管理操作平台**
### 开发语言与主要框架

View File

@@ -10,7 +10,7 @@
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@vueuse/core": "^10.7.0",
"@vueuse/core": "^10.7.2",
"asciinema-player": "^3.6.3",
"axios": "^1.6.2",
"clipboard": "^2.0.11",
@@ -31,9 +31,9 @@
"screenfull": "^6.0.2",
"sortablejs": "^1.15.0",
"splitpanes": "^3.1.5",
"sql-formatter": "^14.0.0",
"sql-formatter": "^15.0.2",
"uuid": "^9.0.1",
"vue": "^3.4.12",
"vue": "^3.4.13",
"vue-router": "^4.2.5",
"xterm": "^5.3.0",
"xterm-addon-fit": "^0.8.0",
@@ -48,7 +48,7 @@
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
"@vitejs/plugin-vue": "^5.0.3",
"@vue/compiler-sfc": "^3.4.12",
"@vue/compiler-sfc": "^3.4.13",
"dotenv": "^16.3.1",
"eslint": "^8.35.0",
"eslint-plugin-vue": "^9.19.2",

View File

@@ -1,12 +1,11 @@
import { h, render, VNode } from 'vue';
import SqlExecDialog from './SqlExecDialog.vue';
import { SqlLanguage } from 'sql-formatter/lib/src/sqlFormatter';
export type SqlExecProps = {
sql: string;
dbId: number;
db: string;
dbType?: SqlLanguage;
dbType?: string;
runSuccessCallback?: Function;
cancelCallback?: Function;
};

View File

@@ -329,11 +329,6 @@ const getNowDbInst = () => {
onMounted(async () => {
console.log('in table data mounted');
state.tableHeight = props.tableHeight;
const columns = await getNowDbInst().loadColumns(props.dbName, props.tableName);
columns.forEach((x: any) => {
x.show = true;
});
state.columns = columns;
await onRefresh();
state.dbDialect = getDbDialect(getNowDbInst().type);
@@ -367,6 +362,14 @@ const selectData = async () => {
const db = props.dbName;
const table = props.tableName;
try {
if (state.columns.length == 0) {
const columns = await getNowDbInst().loadColumns(props.dbName, props.tableName);
columns.forEach((x: any) => {
x.show = true;
});
state.columns = columns;
}
const countRes = await dbInst.runSql(db, dbInst.getDefaultCountSql(table, state.condition));
state.count = countRes.res[0].count || countRes.res[0].COUNT || 0;
let sql = dbInst.getDefaultSelectSql(table, state.condition, state.orderBy, state.pageNum, state.pageSize);

View File

@@ -1,7 +1,6 @@
import { MysqlDialect } from './mysql_dialect';
import { PostgresqlDialect } from './postgres_dialect';
import { DMDialect } from '@/views/ops/db/dialect/dm_dialect';
import { SqlLanguage } from 'sql-formatter/lib/src/sqlFormatter';
import { OracleDialect } from '@/views/ops/db/dialect/oracle_dialect';
import { MariadbDialect } from '@/views/ops/db/dialect/mariadb_dialect';
@@ -92,7 +91,7 @@ export interface DialectInfo {
/**
* 格式化sql的方言
*/
formatSqlDialect: SqlLanguage;
formatSqlDialect: string;
/**
* 列字段类型

View File

@@ -26,8 +26,8 @@ func GetAccountLoginSecurity() *AccountLoginSecurity {
als := new(AccountLoginSecurity)
als.UseCaptcha = c.ConvBool(jm["useCaptcha"], true)
als.UseOtp = c.ConvBool(jm["useOtp"], false)
als.LoginFailCount = c.ConvInt(jm["loginFailCount"], 5)
als.LoginFailMin = c.ConvInt(jm["loginFailMin"], 10)
als.LoginFailCount = stringx.ConvInt(jm["loginFailCount"], 5)
als.LoginFailMin = stringx.ConvInt(jm["loginFailMin"], 10)
otpIssuer := jm["otpIssuer"]
if otpIssuer == "" {
otpIssuer = "mayfly-go"

View File

@@ -10,7 +10,9 @@ import (
"mayfly-go/pkg/base"
"mayfly-go/pkg/contextx"
"mayfly-go/pkg/errorx"
"mayfly-go/pkg/logx"
"mayfly-go/pkg/model"
"mayfly-go/pkg/scheduler"
"mayfly-go/pkg/utils/stringx"
"os"
"path"
@@ -26,6 +28,9 @@ type MachineTermOp interface {
TermConn(ctx context.Context, cli *mcm.Cli, wsConn *websocket.Conn, rows, cols int) error
GetPageList(condition *entity.MachineTermOp, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
// 定时删除终端文件回放记录
TimerDeleteTermOp()
}
func newMachineTermOpApp(machineTermOpRepo repository.MachineTermOp) MachineTermOp {
@@ -38,7 +43,7 @@ type machineTermOpAppImpl struct {
base.AppImpl[*entity.MachineTermOp, repository.MachineTermOp]
}
func (a *machineTermOpAppImpl) TermConn(ctx context.Context, cli *mcm.Cli, wsConn *websocket.Conn, rows, cols int) error {
func (m *machineTermOpAppImpl) TermConn(ctx context.Context, cli *mcm.Cli, wsConn *websocket.Conn, rows, cols int) error {
var recorder *mcm.Recorder
var termOpRecord *entity.MachineTermOp
@@ -83,11 +88,41 @@ func (a *machineTermOpAppImpl) TermConn(ctx context.Context, cli *mcm.Cli, wsCon
if termOpRecord != nil {
now := time.Now()
termOpRecord.EndTime = &now
return a.Insert(ctx, termOpRecord)
return m.Insert(ctx, termOpRecord)
}
return nil
}
func (a *machineTermOpAppImpl) GetPageList(condition *entity.MachineTermOp, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
return a.GetRepo().GetPageList(condition, pageParam, toEntity)
func (m *machineTermOpAppImpl) GetPageList(condition *entity.MachineTermOp, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
return m.GetRepo().GetPageList(condition, pageParam, toEntity)
}
func (m *machineTermOpAppImpl) TimerDeleteTermOp() {
logx.Debug("开始定时删除机器终端回放记录...")
scheduler.AddFun("@every 60m", func() {
startDate := time.Now().AddDate(0, 0, -config.GetMachine().TermOpSaveDays)
cond := &entity.MachineTermOpQuery{
StartCreateTime: &startDate,
}
termOps, err := m.GetRepo().SelectByQuery(cond)
if err != nil {
return
}
basePath := config.GetMachine().TerminalRecPath
for _, termOp := range termOps {
if err := m.DeleteTermOp(basePath, termOp); err != nil {
logx.Warnf("删除终端操作记录失败: %s", err.Error())
}
}
})
}
// 删除终端记录即对应文件
func (m *machineTermOpAppImpl) DeleteTermOp(basePath string, termOp *entity.MachineTermOp) error {
if err := m.DeleteById(context.Background(), termOp.Id); err != nil {
return err
}
return os.Remove(path.Join(basePath, termOp.RecordFilePath))
}

View File

@@ -4,6 +4,7 @@ import (
sysapp "mayfly-go/internal/sys/application"
"mayfly-go/pkg/logx"
"mayfly-go/pkg/utils/bytex"
"mayfly-go/pkg/utils/stringx"
)
const (
@@ -13,6 +14,7 @@ const (
type Machine struct {
TerminalRecPath string // 终端操作记录存储位置
UploadMaxFileSize int64 // 允许上传的最大文件size
TermOpSaveDays int // 终端记录保存天数
}
// 获取机器相关配置
@@ -39,5 +41,6 @@ func GetMachine() *Machine {
}
}
mc.UploadMaxFileSize = uploadMaxFileSize
mc.TermOpSaveDays = stringx.ConvInt(jm["termOpSaveDays"], 30)
return mc
}

View File

@@ -1,5 +1,7 @@
package entity
import "time"
type MachineQuery struct {
Ids string `json:"ids" form:"ids"`
Name string `json:"name" form:"name"`
@@ -15,3 +17,7 @@ type AuthCertQuery struct {
Name string `json:"name" form:"name"`
AuthMethod string `json:"authMethod" form:"authMethod"` // IP地址
}
type MachineTermOpQuery struct {
StartCreateTime *time.Time
}

View File

@@ -11,4 +11,7 @@ type MachineTermOp interface {
// 分页获取机器终端执行记录列表
GetPageList(condition *entity.MachineTermOp, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
// 根据条件获取记录列表
SelectByQuery(cond *entity.MachineTermOpQuery) ([]*entity.MachineTermOp, error)
}

View File

@@ -20,3 +20,11 @@ func (m *machineTermOpRepoImpl) GetPageList(condition *entity.MachineTermOp, pag
qd := gormx.NewQuery(condition).WithCondModel(condition).WithOrderBy(orderBy...)
return gormx.PageQuery(qd, pageParam, toEntity)
}
// 根据条件获取记录列表
func (m *machineTermOpRepoImpl) SelectByQuery(cond *entity.MachineTermOpQuery) ([]*entity.MachineTermOp, error) {
qd := gormx.NewQuery(m.GetModel()).Le("create_time", cond.StartCreateTime)
var res []*entity.MachineTermOp
err := gormx.ListByQueryCond(qd, &res)
return res, err
}

View File

@@ -14,6 +14,8 @@ func Init() {
application.GetMachineApp().TimerUpdateStats()
application.GetMachineTermOpApp().TimerDeleteTermOp()
global.EventBus.Subscribe(consts.DeleteMachineEventTopic, "machineFile", func(ctx context.Context, event *eventbus.Event) error {
me := event.Val.(*entity.Machine)
return application.GetMachineFileApp().DeleteByCond(ctx, &entity.MachineFile{MachineId: me.Id})

View File

@@ -3,7 +3,7 @@ package entity
import (
"encoding/json"
"mayfly-go/pkg/model"
"strconv"
"mayfly-go/pkg/utils/stringx"
)
const (
@@ -49,7 +49,7 @@ func (c *Config) IntValue(defaultValue int) int {
if c.Id == 0 {
return defaultValue
}
return c.ConvInt(c.Value, defaultValue)
return stringx.ConvInt(c.Value, defaultValue)
}
// 转换配置中的值为bool类型默认"1"或"true"为true其他为false
@@ -59,15 +59,3 @@ func (c *Config) ConvBool(value string, defaultValue bool) bool {
}
return value == "1" || value == "true"
}
// 转换配置值中的值为int
func (c *Config) ConvInt(value string, defaultValue int) int {
if value == "" {
return defaultValue
}
if intV, err := strconv.Atoi(value); err != nil {
return defaultValue
} else {
return intV
}
}

View File

@@ -0,0 +1,17 @@
package stringx
import (
"strconv"
)
// 将字符串值转为int值, 若value为空或者转换失败则返回默认值
func ConvInt(value string, defaultValue int) int {
if value == "" {
return defaultValue
}
if intV, err := strconv.Atoi(value); err != nil {
return defaultValue
} else {
return intV
}
}

View File

@@ -622,7 +622,7 @@ INSERT INTO `t_sys_config` (name, `key`, params, value, remark, permission, crea
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('系统全局样式设置', 'SysStyleConfig', '[{"model":"logoIcon","name":"logo图标","placeholder":"系统logo图标base64编码, 建议svg格式不超过10k","required":false},{"model":"title","name":"菜单栏标题","placeholder":"系统菜单栏标题展示","required":false},{"model":"viceTitle","name":"登录页标题","placeholder":"登录页标题展示","required":false},{"model":"useWatermark","name":"是否启用水印","placeholder":"是否启用系统水印","options":"true,false","required":false},{"model":"watermarkContent","name":"水印补充信息","placeholder":"额外水印信息","required":false}]', '{"title":"mayfly-go","viceTitle":"mayfly-go","logoIcon":"","useWatermark":"true","watermarkContent":""}', '系统icon、标题、水印信息等配置', 'all', '2024-01-04 15:17:18', 1, 'admin', '2024-01-05 09:40:44', 1, 'admin', 0, NULL);
INSERT INTO `t_sys_config` (name, `key`, params, value, remark, create_time, creator_id, creator, update_time, modifier_id, modifier)VALUES ('数据库查询最大结果集', 'DbQueryMaxCount', '[]', '200', '允许sql查询的最大结果集数。注: 0=不限制', '2023-02-11 14:29:03', 1, 'admin', '2023-02-11 14:40:56', 1, 'admin');
INSERT INTO `t_sys_config` (name, `key`, params, value, remark, create_time, creator_id, creator, update_time, modifier_id, modifier)VALUES ('数据库是否记录查询SQL', 'DbSaveQuerySQL', '[]', '0', '1: 记录、0:不记录', '2023-02-11 16:07:14', 1, 'admin', '2023-02-11 16:44:17', 1, 'admin');
INSERT INTO `t_sys_config` (name, `key`, params, value, remark, permission, create_time, creator_id, creator, update_time, modifier_id, modifier, is_deleted, delete_time) VALUES('机器相关配置', 'MachineConfig', '[{"name":"终端回放存储路径","model":"terminalRecPath","placeholder":"终端回放存储路径"},{"name":"uploadMaxFileSize","model":"uploadMaxFileSize","placeholder":"允许上传的最大文件大小(1MB\\\\2GB等)"}]', '{"terminalRecPath":"./rec","uploadMaxFileSize":"1GB"}', '机器相关配置,如终端回放路径等', 'admin,', '2023-07-13 16:26:44', 1, 'admin', '2023-11-09 22:01:31', 1, 'admin', 0, NULL);
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('机器相关配置', 'MachineConfig', '[{"name":"终端回放存储路径","model":"terminalRecPath","placeholder":"终端回放存储路径"},{"name":"uploadMaxFileSize","model":"uploadMaxFileSize","placeholder":"允许上传的最大文件大小(1MB\\2GB等)"},{"model":"termOpSaveDays","name":"终端记录保存时间","placeholder":"终端记录保存时间(单位天)"}]', '{"terminalRecPath":"./rec","uploadMaxFileSize":"100MB"}', '机器相关配置,如终端回放路径等', 'all', '2023-07-13 16:26:44', 1, 'admin', '2024-01-15 16:30:22', 1, 'admin', 0, NULL);
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('数据库备份恢复', 'DbBackupRestore', '[{"model":"backupPath","name":"备份路径","placeholder":"备份文件存储路径"}]', '{"backupPath":"./db/backup"}', '', 'admin,', '2023-12-29 09:55:26', 1, 'admin', '2023-12-29 15:45:24', 1, 'admin', 0, NULL);
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('Mysql可执行文件', 'MysqlBin', '[{"model":"path","name":"路径","placeholder":"可执行文件路径","required":true},{"model":"mysql","name":"mysql","placeholder":"mysql命令路径(空则为 路径/mysql)","required":false},{"model":"mysqldump","name":"mysqldump","placeholder":"mysqldump命令路径(空则为 路径/mysqldump)","required":false},{"model":"mysqlbinlog","name":"mysqlbinlog","placeholder":"mysqlbinlog命令路径(空则为 路径/mysqlbinlog)","required":false}]', '{"mysql":"","mysqldump":"","mysqlbinlog":"","path":"./db/mysql/bin"}', '', 'admin,', '2023-12-29 10:01:33', 1, 'admin', '2023-12-29 13:34:40', 1, 'admin', 0, NULL);
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('MariaDB可执行文件', 'MariadbBin', '[{"model":"path","name":"路径","placeholder":"可执行文件路径","required":true},{"model":"mysql","name":"mysql","placeholder":"mysql命令路径(空则为 路径/mysql)","required":false},{"model":"mysqldump","name":"mysqldump","placeholder":"mysqldump命令路径(空则为 路径/mysqldump)","required":false},{"model":"mysqlbinlog","name":"mysqlbinlog","placeholder":"mysqlbinlog命令路径(空则为 路径/mysqlbinlog)","required":false}]', '{"mysql":"","mysqldump":"","mysqlbinlog":"","path":"./db/mariadb/bin"}', '', 'admin,', '2023-12-29 10:01:33', 1, 'admin', '2023-12-29 13:34:40', 1, 'admin', 0, NULL);