package output import ( "fmt" "os" "path/filepath" "sync" "time" "github.com/shadow1ng/fscan/common/i18n" ) // Manager 输出管理器 type Manager struct { mu sync.RWMutex config *ManagerConfig writer OutputWriter reader OutputReader statistics *Statistics buffer []*ScanResult bufferMutex sync.Mutex flushTicker *time.Ticker stopChan chan struct{} initialized bool closed bool } // NewManager 创建新的输出管理器 func NewManager(config *ManagerConfig) (*Manager, error) { if config == nil { return nil, fmt.Errorf(i18n.GetText("output_config_nil")) } // 验证输出格式 if err := validateFormat(config.Format); err != nil { return nil, err } // 创建输出目录 if err := createOutputDir(config.OutputPath); err != nil { return nil, err } manager := &Manager{ config: config, statistics: NewStatistics(), stopChan: make(chan struct{}), } // 初始化写入器 if err := manager.initializeWriter(); err != nil { return nil, err } // 初始化读取器 manager.initializeReader() // 如果启用缓冲,初始化缓冲区 if config.EnableBuffer { manager.buffer = make([]*ScanResult, 0, config.BufferSize) // 如果启用自动刷新,启动定时器 if config.AutoFlush { manager.startAutoFlush() } } manager.initialized = true return manager, nil } // validateFormat 验证输出格式 func validateFormat(format OutputFormat) error { switch format { case FormatTXT, FormatJSON, FormatCSV: return nil default: return fmt.Errorf(i18n.GetText("output_unsupported_format"), format) } } // createOutputDir 创建输出目录 func createOutputDir(outputPath string) error { dir := filepath.Dir(outputPath) return os.MkdirAll(dir, DefaultDirPermissions) } // initializeWriter 初始化写入器 func (m *Manager) initializeWriter() error { var writer OutputWriter var err error switch m.config.Format { case FormatTXT: writer, err = NewTXTWriter(m.config.OutputPath) case FormatJSON: writer, err = NewJSONWriter(m.config.OutputPath) case FormatCSV: writer, err = NewCSVWriter(m.config.OutputPath) default: return fmt.Errorf(i18n.GetText("output_unsupported_format"), m.config.Format) } if err != nil { return fmt.Errorf(i18n.GetText("output_writer_init_failed"), err) } m.writer = writer // 写入头部(如果需要) return m.writer.WriteHeader() } // initializeReader 初始化读取器 func (m *Manager) initializeReader() { // 目前只有CSV格式支持读取 if m.config.Format == FormatCSV { m.reader = NewCSVReader(m.config.OutputPath) } } // startAutoFlush 启动自动刷新 func (m *Manager) startAutoFlush() { m.flushTicker = time.NewTicker(m.config.FlushInterval) go func() { for { select { case <-m.flushTicker.C: m.flushBuffer() case <-m.stopChan: return } } }() } // SaveResult 保存扫描结果 func (m *Manager) SaveResult(result *ScanResult) error { m.mu.RLock() defer m.mu.RUnlock() if !m.initialized { return fmt.Errorf(i18n.GetText("output_manager_not_init")) } if m.closed { return fmt.Errorf(i18n.GetText("output_manager_closed")) } // 更新统计信息 m.statistics.AddResult(result.Type) // 如果启用缓冲,先添加到缓冲区 if m.config.EnableBuffer { return m.addToBuffer(result) } // 直接写入 return m.writer.Write(result) } // addToBuffer 添加结果到缓冲区 func (m *Manager) addToBuffer(result *ScanResult) error { m.bufferMutex.Lock() defer m.bufferMutex.Unlock() m.buffer = append(m.buffer, result) // 如果缓冲区已满,立即刷新 if len(m.buffer) >= m.config.BufferSize { return m.flushBufferUnsafe() } return nil } // flushBuffer 刷新缓冲区(加锁版本) func (m *Manager) flushBuffer() error { m.bufferMutex.Lock() defer m.bufferMutex.Unlock() return m.flushBufferUnsafe() } // flushBufferUnsafe 刷新缓冲区(无锁版本,内部使用) func (m *Manager) flushBufferUnsafe() error { if len(m.buffer) == 0 { return nil } // 批量写入 for _, result := range m.buffer { if err := m.writer.Write(result); err != nil { return fmt.Errorf(i18n.GetText("output_write_failed"), err) } } // 刷新写入器 if err := m.writer.Flush(); err != nil { return fmt.Errorf(i18n.GetText("output_flush_failed"), err) } // 清空缓冲区 m.buffer = m.buffer[:0] return nil } // ============================================================================================= // 已删除的死代码(未使用): // GetResults, GetResultsWithFilter, GetStatistics, Flush 方法 // ============================================================================================= // Close 关闭输出管理器 func (m *Manager) Close() error { m.mu.Lock() defer m.mu.Unlock() if m.closed { return nil } // 停止自动刷新 if m.flushTicker != nil { m.flushTicker.Stop() close(m.stopChan) } // 最后一次刷新缓冲区 if m.config.EnableBuffer { m.flushBufferUnsafe() } // 关闭写入器 var err error if m.writer != nil { err = m.writer.Close() } // 关闭读取器 if m.reader != nil { if closeErr := m.reader.Close(); closeErr != nil && err == nil { err = closeErr } } m.closed = true return err } // ============================================================================================= // 已删除的死代码(未使用): // IsInitialized, IsClosed, GetConfig, UpdateConfig 方法 // ============================================================================================= // ============================================================================================= // 已删除的死代码(未使用):globalManager 全局变量及 SetGlobalManager 函数 // =============================================================================================