新增: 文件操作增强与预览扩展

- 文件剪贴板复制剪切粘贴,重名自动副本
- SFTP下载到本机与外部文件拖入,目录递归
- 传输进度浮动面板,transfer-progress事件链
- Drawio预览,Excel工作线程,冻结看门狗
- cmd与bat自写batch语法高亮,psm1等映射补齐
This commit is contained in:
lxy
2026-09-15 22:26:12 +08:00
parent f1bc5b49f1
commit e7a2c5148e
59 changed files with 3185 additions and 2047 deletions
+52 -56
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"time"
)
@@ -18,6 +19,7 @@ const (
OperationDelete AuditOperation = "delete" // 删除文件
OperationCreate AuditOperation = "create" // 创建目录
OperationRename AuditOperation = "rename" // 重命名
OperationCopy AuditOperation = "copy" // 复制
OperationMove AuditOperation = "move" // 移动
OperationList AuditOperation = "list" // 列出目录
OperationDownload AuditOperation = "download" // 下载
@@ -39,43 +41,45 @@ type AuditLogEntry struct {
// AuditLogger 审计日志记录器
type AuditLogger struct {
logFile *os.File
logPath string
mu sync.Mutex
buffer []AuditLogEntry
logFile *os.File
logDir string
mu sync.Mutex
buffer []AuditLogEntry
bufferSize int
stopChan chan struct{}
stopChan chan struct{}
initialized bool // 懒初始化标志(失败时允许重试)
}
// NewAuditLogger 创建审计日志记录器
// NewAuditLogger 创建审计日志记录器(延迟初始化,不立即打开文件)
func NewAuditLogger(logDir string) (*AuditLogger, error) {
// 创建日志目录
if err := os.MkdirAll(logDir, 0755); err != nil {
return nil, fmt.Errorf("创建日志目录失败: %v", err)
}
// 生成日志文件名(按日期)
timestamp := time.Now().Format("2006-01-02")
logPath := filepath.Join(logDir, fmt.Sprintf("audit_%s.log", timestamp))
// 打开日志文件(追加模式)
logFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return nil, fmt.Errorf("打开日志文件失败: %v", err)
}
logger := &AuditLogger{
logFile: logFile,
logPath: logPath,
return &AuditLogger{
logDir: logDir,
buffer: make([]AuditLogEntry, 0, 100),
bufferSize: 100, // 缓冲100条记录后批量写入
bufferSize: 100,
stopChan: make(chan struct{}),
}, nil
}
// ensureReady 首次写入时才创建目录、打开文件、启动后台协程
// 在 a.mu.Lock 保护下调用,失败时下次 Log 会重试
func (a *AuditLogger) ensureReady() error {
if a.initialized {
return nil
}
// 启动后台协程,定期刷新缓冲区
go logger.backgroundFlush()
return logger, nil
if err := os.MkdirAll(a.logDir, 0755); err != nil {
return fmt.Errorf("创建日志目录失败: %v", err)
}
timestamp := time.Now().Format("2006-01-02")
f, err := os.OpenFile(
filepath.Join(a.logDir, fmt.Sprintf("audit_%s.log", timestamp)),
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return err
}
a.logFile = f
a.initialized = true
go a.backgroundFlush()
return nil
}
// Log 记录操作日志
@@ -88,6 +92,13 @@ func (a *AuditLogger) Log(entry AuditLogEntry) error {
a.mu.Lock()
defer a.mu.Unlock()
// 懒初始化:首次写入时才打开文件
if a.logFile == nil {
if err := a.ensureReady(); err != nil {
return err
}
}
// 添加到缓冲区
a.buffer = append(a.buffer, entry)
@@ -211,6 +222,11 @@ func (a *AuditLogger) Close() error {
a.mu.Lock()
defer a.mu.Unlock()
// 从未写入过日志,无需关闭
if a.logFile == nil {
return nil
}
// 刷新剩余缓冲区
if err := a.flush(); err != nil {
return err
@@ -251,35 +267,15 @@ func GetRecentLogs(logDir string, limit int) ([]AuditLogEntry, error) {
return entries, nil
}
// parseLines 解析文本为行
// parseLines 解析文本为行(过滤空行)
func parseLines(text string) []string {
lines := make([]string, 0)
current := ""
for _, ch := range text {
if ch == '\n' {
if current != "" {
lines = append(lines, current)
current = ""
}
} else {
current += string(ch)
raw := strings.Split(text, "\n")
lines := make([]string, 0, len(raw))
for _, line := range raw {
if line != "" {
lines = append(lines, line)
}
}
if current != "" {
lines = append(lines, current)
}
return lines
}
// 全局审计日志记录器
var globalAuditLogger *AuditLogger
var auditLoggerOnce sync.Once
// GetAuditLogger 获取全局审计日志记录器
func GetAuditLogger() *AuditLogger {
return globalAuditLogger
}