From 92cb9267fc15c429e47826799bb8678010ac2239 Mon Sep 17 00:00:00 2001 From: Kirillkriv Date: Sun, 16 Aug 2026 22:39:42 +0500 Subject: [PATCH] feat: exporter api, json exporter --- internal/adapters/exporter/exporter.go | 43 ++++++++++++++++++++++++++ internal/adapters/json/json.go | 34 ++++++++++++++++++++ internal/models/models.go | 12 +++---- 3 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 internal/adapters/exporter/exporter.go create mode 100644 internal/adapters/json/json.go diff --git a/internal/adapters/exporter/exporter.go b/internal/adapters/exporter/exporter.go new file mode 100644 index 0000000..43bfe7c --- /dev/null +++ b/internal/adapters/exporter/exporter.go @@ -0,0 +1,43 @@ +package exporter + +import ( + "context" + "fmt" + "github.com/abelith/spellbook/internal/models" + "io" + "sync" +) + +type Exporter interface { + Export(ctx context.Context, ch <-chan models.Spell, w io.Writer) error +} + +var ( + exporters = make(map[string]Exporter) + mu sync.Mutex +) + +func Register(name string, exp Exporter) { + mu.Lock() + defer mu.Unlock() + + if exp == nil { + panic("exporter: Exporter cannot be nil") + } + if _, ok := exporters[name]; ok { + panic("exporter: Register called twice for " + name) + } + exporters[name] = exp +} + +func Export(ctx context.Context, name string, ch <-chan models.Spell, w io.Writer) error { + mu.Lock() + exp, ok := exporters[name] + mu.Unlock() + + if !ok { + return fmt.Errorf("exporter %s not found", name) + } + + return exp.Export(ctx, ch, w) +} diff --git a/internal/adapters/json/json.go b/internal/adapters/json/json.go new file mode 100644 index 0000000..1367903 --- /dev/null +++ b/internal/adapters/json/json.go @@ -0,0 +1,34 @@ +package json + +import ( + "context" + "encoding/json" + "github.com/abelith/spellbook/internal/adapters/exporter" + "github.com/abelith/spellbook/internal/models" + "io" +) + +func init() { + exporter.Register("jsonl", &JsonlExporter{}) +} + +type JsonlExporter struct{} + +func (je *JsonlExporter) Export(ctx context.Context, ch <-chan models.Spell, w io.Writer) error { + encoder := json.NewEncoder(w) + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case spell, ok := <-ch: + if !ok { + return nil + } + + if err := encoder.Encode(&spell); err != nil { + return err + } + } + } +} diff --git a/internal/models/models.go b/internal/models/models.go index 96ac3c6..2575a5b 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -6,12 +6,12 @@ import ( ) type Spell struct { - Id int - Name string - Spell string - ShortDesc string - Description string - Tags []string + Id int `json:"-"` + Name string `json:"name,omitempty"` + Spell string `json:"spell,omitempty"` + ShortDesc string `json:"short_desc,omitempty"` + Description string `json:"description,omitempty"` + Tags []string `json:"tags,omitempty"` } type SpellCast struct {