init: initial commit
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user