新增: 文件操作增强与预览扩展
- 文件剪贴板复制剪切粘贴,重名自动副本 - SFTP下载到本机与外部文件拖入,目录递归 - 传输进度浮动面板,transfer-progress事件链 - Drawio预览,Excel工作线程,冻结看门狗 - cmd与bat自写batch语法高亮,psm1等映射补齐
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user