hako/internal/extractors/manager.go
2026-01-12 19:35:18 +01:00

127 lines
3 KiB
Go

package extractors
import (
"fmt"
"log/slog"
"sort"
"sync"
)
// extractorStatus tracks the initialization status of an extractor
type extractorStatus struct {
extractor Extractor
available bool
errorMsg string
}
// Manager manages all registered extractors
type Manager struct {
extractors map[string]*extractorStatus
mu sync.RWMutex
logger *slog.Logger
}
// NewManager creates a new extractor manager
func NewManager(logger *slog.Logger) *Manager {
return &Manager{
extractors: make(map[string]*extractorStatus),
logger: logger,
}
}
// Register registers an extractor
// If Init() fails, the error is logged but registration continues
func (m *Manager) Register(extractor Extractor) error {
m.mu.Lock()
defer m.mu.Unlock()
key := extractor.Key()
if _, exists := m.extractors[key]; exists {
return fmt.Errorf("extractor with key %s already registered", key)
}
// Initialize the extractor
err := extractor.Init()
available := err == nil
errorMsg := ""
if err != nil {
m.logger.Error("Failed to initialize extractor",
"key", key,
"name", extractor.Name(),
"error", err)
errorMsg = err.Error()
// Continue registration even if Init() fails - extractor will be marked as unavailable
}
m.extractors[key] = &extractorStatus{
extractor: extractor,
available: available,
errorMsg: errorMsg,
}
return nil
}
// GetExtractorForMimeType retrieves an extractor that supports the given MIME type
func (m *Manager) GetExtractorForMimeType(mimeType string) (Extractor, bool) {
m.mu.RLock()
defer m.mu.RUnlock()
for _, status := range m.extractors {
if !status.available {
continue // Skip unavailable extractors
}
for _, supportedType := range status.extractor.SupportedMimeTypes() {
if supportedType == mimeType {
return status.extractor, true
}
}
}
return nil, false
}
// List returns all registered extractors
func (m *Manager) List() []Extractor {
m.mu.RLock()
defer m.mu.RUnlock()
var all []Extractor
for _, status := range m.extractors {
all = append(all, status.extractor)
}
return all
}
// ExtractorStatus represents the status of an extractor
type ExtractorStatus struct {
Key string `json:"key"`
Name string `json:"name"`
SupportedMimeTypes []string `json:"supported_mime_types"`
Available bool `json:"available"`
ErrorMessage string `json:"error_message,omitempty"`
}
// GetStatus returns status information for all registered extractors
func (m *Manager) GetStatus() []ExtractorStatus {
m.mu.RLock()
defer m.mu.RUnlock()
var statuses []ExtractorStatus
for _, status := range m.extractors {
statuses = append(statuses, ExtractorStatus{
Key: status.extractor.Key(),
Name: status.extractor.Name(),
SupportedMimeTypes: status.extractor.SupportedMimeTypes(),
Available: status.available,
ErrorMessage: status.errorMsg,
})
}
// Sort by name
sort.Slice(statuses, func(i, j int) bool {
return statuses[i].Name < statuses[j].Name
})
return statuses
}