135 lines
3.1 KiB
Go
135 lines
3.1 KiB
Go
package parser
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"sync"
|
|
|
|
"github.com/wailsapp/wails/v3/pkg/application"
|
|
)
|
|
|
|
// Job represents a file parsing task.
|
|
type Job struct {
|
|
FilePath string
|
|
FileID string
|
|
ProjectID string
|
|
}
|
|
|
|
// Result is the outcome of a parsing job.
|
|
type Result struct {
|
|
Job Job
|
|
Content string
|
|
Err error
|
|
}
|
|
|
|
// ProcessingQueue manages concurrent file parsing with a worker pool.
|
|
type ProcessingQueue struct {
|
|
registry *Registry
|
|
jobs chan Job
|
|
results chan Result
|
|
concurrency int
|
|
wg sync.WaitGroup
|
|
onComplete func(Result)
|
|
}
|
|
|
|
// NewProcessingQueue creates a queue with the given concurrency limit.
|
|
func NewProcessingQueue(registry *Registry, concurrency int, onComplete func(Result)) *ProcessingQueue {
|
|
q := &ProcessingQueue{
|
|
registry: registry,
|
|
jobs: make(chan Job, 100),
|
|
results: make(chan Result, 100),
|
|
concurrency: concurrency,
|
|
onComplete: onComplete,
|
|
}
|
|
q.start()
|
|
return q
|
|
}
|
|
|
|
func (q *ProcessingQueue) start() {
|
|
// Start workers
|
|
for i := 0; i < q.concurrency; i++ {
|
|
go q.worker(i)
|
|
}
|
|
// Start result collector
|
|
go func() {
|
|
for result := range q.results {
|
|
if q.onComplete != nil {
|
|
q.onComplete(result)
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (q *ProcessingQueue) worker(id int) {
|
|
for job := range q.jobs {
|
|
slog.Info("parser worker processing", "worker", id, "file", job.FilePath)
|
|
content, err := q.registry.Parse(job.FilePath)
|
|
if err != nil {
|
|
slog.Error("parse failed", "file", job.FilePath, "err", err)
|
|
}
|
|
q.results <- Result{Job: job, Content: content, Err: err}
|
|
q.wg.Done()
|
|
}
|
|
}
|
|
|
|
// Submit adds a job to the processing queue.
|
|
func (q *ProcessingQueue) Submit(job Job) {
|
|
q.wg.Add(1)
|
|
q.jobs <- job
|
|
}
|
|
|
|
// Wait blocks until all queued jobs are complete.
|
|
func (q *ProcessingQueue) Wait() {
|
|
q.wg.Wait()
|
|
}
|
|
|
|
// Close shuts down the queue.
|
|
func (q *ProcessingQueue) Close() {
|
|
close(q.jobs)
|
|
q.wg.Wait()
|
|
close(q.results)
|
|
}
|
|
|
|
// ParseService wraps the parsing pipeline for Wails binding.
|
|
type ParseService struct {
|
|
registry *Registry
|
|
queue *ProcessingQueue
|
|
}
|
|
|
|
// NewParseService creates a new parse service.
|
|
func NewParseService() *ParseService {
|
|
return &ParseService{
|
|
registry: NewRegistry(),
|
|
}
|
|
}
|
|
|
|
// ParseFile synchronously parses a single file. For Wails binding.
|
|
func (s *ParseService) ParseFile(path string) (string, error) {
|
|
content, err := s.registry.Parse(path)
|
|
if err != nil {
|
|
return "", fmt.Errorf("parse %s: %w", path, err)
|
|
}
|
|
return content, nil
|
|
}
|
|
|
|
// GetSupportedTypes returns supported file extensions.
|
|
func (s *ParseService) GetSupportedTypes() []string {
|
|
return []string{".xlsx", ".xls", ".pdf", ".dwg", ".dxf", ".docx"}
|
|
}
|
|
|
|
// ParseDeliveryStandard opens a file dialog to select a document, parses it, and returns the markdown.
|
|
func (s *ParseService) ParseDeliveryStandard() (string, error) {
|
|
dialog := application.Get().Dialog.OpenFile()
|
|
dialog.SetTitle("选择交付标准文件 (Delivery Standard)")
|
|
dialog.AddFilter("Documents", "*.pdf;*.xlsx;*.xls;*.docx")
|
|
|
|
path, err := dialog.PromptForSingleSelection()
|
|
if err != nil {
|
|
return "", fmt.Errorf("open file dialog: %w", err)
|
|
}
|
|
if path == "" {
|
|
return "", nil // user cancelled
|
|
}
|
|
return s.ParseFile(path)
|
|
}
|