esgallery

package
v0.0.31 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2023 License: MIT Imports: 28 Imported by: 0

README

esgallery – Event-sourced Image Galleries

Package esgallery implements an event-sourced image gallery aggregate on top of goes and the non event-sourced implementation The Gallery provided by this package can be embedded into your own aggregates that need to implement an image gallery.

Example

In this example, we use UUIDs for the ids of stacks and variants. Read the documentation of the non event-sourced implementation for more details.

package myapp

import (
  "github.com/google/uuid"
  "github.com/modernice/goes/aggregate"
  "github.com/modernice/media-entity/goes/esgallery"
)

const GalleryAggregate = "myapp.gallery"

type Gallery struct {
  *aggregate.Base
  *esgallery.Gallery[uuid.UUID, uuid.UUID, *Gallery]
}

type GalleryRepository = aggregate.TypedRepository[*Gallery]

func NewGallery(id uuid.UUID) *Gallery {
  g:= &Gallery{Base: aggregate.New(GalleryAggregate, id)}
  g.Gallery = esgallery.New[uuid.UUID, uuid.UUID](g)
  return g
}
2. Setup uploader
package myapp

import (
  "github.com/google/uuid"
  "github.com/modernice/goes/aggregate"
  "github.com/modernice/goes/aggregate/repository"
  "github.com/modernice/goes/event"
  "github.com/modernice/media-entity/goes/esgallery"
)

// Create an alias to avoid having to type *esgallery.Uploader[uuid.UUID, uuid.UUID] everywhere.
type Uploader = esgallery.Uploader[uuid.UUID, uuid.UUID]

// NewUploader returns an uploader for gallery images. The two type parameters
// specify the ID types for the stacks and variants within the gallery aggregate.
func NewUploader() *Uploader {
  // Create storage for gallery images.
  var storage esgallery.MemoryStorage

  // Create a new Uploader using the storage.
  return esgallery.NewUploader[uuid.UUID, uuid.UUID](&storage)
}
2. Setup post-processing
package myapp

import (
  "github.com/google/uuid"
  "github.com/modernice/goes/aggregate"
  "github.com/modernice/goes/aggregate/repository"
  "github.com/modernice/goes/event"
  "github.com/modernice/media-entity/goes/esgallery"
)

// Create an alias to avoid having to type *esgallery.PostProcessor[*Gallery, uuid.UUID, uuid.UUID] everywhere.
type PostProcessor = esgallery.PostProcessor[*Gallery, uuid.UUID, uuid.UUID]

func Setup(uploader *Uploader, bus event.Bus, repo aggregate.Repository) *PostProcessor {
  // Create storage for gallery images.
  var storage esgallery.MemoryStorage

  // Create an image processor for galleries.
  p := esgallery.NewProcessor(esgallery.DefaultEncoder, &storage, uploader, uuid.New)

  // Create the PostProcessor from the Processor.
  galleries := repository.Typed(repo, NewGallery)
  pp := esgallery.NewPostProcessor(p, bus, galleries.Fetch)

  return pp
}
3. Run post-processor

The PostProcessor runs in the background and processes images whenever a new stack is added to a galllery, or when the original variant of a stack is replaced.

package myapp

import (
  "context"
  "github.com/modernice/media-entity/goes/esgallery"
  "github.com/modernice/media-tools/image"
  "github.com/modernice/media-tools/image/compression"
)

func run(pp *PostProcessor, galleries GalleryRepository) {
  // Setup a processing pipeline
  pipeline := image.Pipeline{
    image.Resize(image.DimensionMap{
      "sm": {640},
      "md": {960},
      "lg": {1280},
      "xl": {1920},
    }),
    image.Compress(compression.JPEG(80)),
  }

  // Start the post-processor as a background task
  results, errs, err := pp.Run(context.TODO(), pipeline)
  if err != nil {
    panic(err)
  }

  // Log processing errors
	go func(){
    for err := range errs {
      log.Printf("post-processor: %v", err)
    }
  }()

  for result := range results {
    g, err := galleries.Fetch(context.TODO(), result.Gallery.ID)
    if err != nil {
      panic(fmt.Errorf("fetch gallery: %w", err))
    }

    if err := result.Apply(g); err != nil {
      panic(fmt.Errorf("apply processor result: %w", err))
    }

    if err := galleries.Save(context.TODO(), result); err != nil {
      panic(fmt.Errorf("save gallery: %w", err))
    }
  }
}

Documentation

Index

Constants

View Source
const (
	AddStackCmd       = "esgallery.add_stack"
	RemoveStackCmd    = "esgallery.remove_stack"
	ClearStackCmd     = "esgallery.clear_stack"
	AddVariantsCmd    = "esgallery.add_variants"
	AddVariantCmd     = "esgallery.add_variant"
	RemoveVariantCmd  = "esgallery.remove_variant"
	ReplaceVariantCmd = "esgallery.replace_variant"
	TagStackCmd       = "esgallery.tag_stack"
	UntagStackCmd     = "esgallery.untag_stack"
	SortCmd           = "esgallery.sort"
	ClearCmd          = "esgallery.clear"
)

Gallery commands

View Source
const (
	StackAdded      = "esgallery.stack_added"
	StackRemoved    = "esgallery.stack_removed"
	StackCleared    = "esgallery.stack_cleared"
	VariantsAdded   = "esgallery.variants_added"
	VariantAdded    = "esgallery.variant_added"
	VariantRemoved  = "esgallery.variant_removed"
	VariantReplaced = "esgallery.variant_replaced"
	StackTagged     = "esgallery.stack_tagged"
	StackUntagged   = "esgallery.stack_untagged"
	Sorted          = "esgallery.sorted"
	Cleared         = "esgallery.cleared"
)

Gallery events

View Source
const ProcessedTag = "processed"

ProcessedTag is added to [gallery.Stack]s that were processed by a *PostProcessor.

View Source
const (
	StackProcessed = "esgallery.stack_processed"
)

Non-aggregate events

Variables

View Source
var ErrMissingEncoder = errors.New("missing encoder for this content-type")

ErrMissingEncoder is returned by Encoder.Encode if no encoder is registered for the given content-type.

View Source
var ProcessorTriggerEvents = []string{
	StackAdded,
}

ProcessorTriggerEvents are the events that can trigger a *Processor.

Functions

func RegisterCommands

func RegisterCommands[StackID, ImageID ID](r codec.Registerer)

RegisterCommands registers Gallery commands into a command registry.

func RegisterEvents

func RegisterEvents[StackID, ImageID ID](r codec.Registerer)

RegisterEvents registers the *Gallery events into an event registry.

func WasProcessed added in v0.0.6

func WasProcessed[StackID, ImageID gallery.ID](s gallery.Stack[StackID, ImageID]) bool

WasProcessed returns whether the given gallery.Stack was processed by a *PostProcessor.

Types

type ApplyResultOption

type ApplyResultOption func(*applyResultConfig)

ApplyResultOption is an option for ProcessorResult.Apply.

func ClearStack

func ClearStack(clear bool) ApplyResultOption

ClearStack returns an ApplyResultOption that clears the variants of the gallery.Stack before adding the processed variants to the Stack.

type Commands

type Commands[StackID, ImageID ID] struct {
	// contains filtered or unexported fields
}

Commands is a factory for Gallery commands.

func NewCommands

func NewCommands[StackID, ImageID ID](aggregateName string) *Commands[StackID, ImageID]

NewCommands returns a factory for creating commands and command handlers.

func (*Commands[StackID, ImageID]) AddStack

func (c *Commands[StackID, ImageID]) AddStack(galleryID uuid.UUID, stackID StackID, img gallery.Image[ImageID]) command.Cmd[addStack[StackID, ImageID]]

AddStack returns the command to add a new gallery.Stack to a *Gallery.

func (*Commands[StackID, ImageID]) AddVariant

func (c *Commands[StackID, ImageID]) AddVariant(galleryID uuid.UUID, stackID StackID, img gallery.Image[ImageID]) command.Cmd[addVariant[StackID, ImageID]]

AddVariant returns the command to add a new [Variant] to a gallery.Stack in a *Gallery.

func (*Commands[StackID, ImageID]) AddVariants added in v0.0.19

func (c *Commands[StackID, ImageID]) AddVariants(galleryID uuid.UUID, stackID StackID, variants []gallery.Image[ImageID]) command.Cmd[addVariants[StackID, ImageID]]

AddVariants returns the command to add a multiple [Variant]s to a gallery.Stack in a *Gallery.

func (*Commands[StackID, ImageID]) Clear added in v0.0.12

func (c *Commands[StackID, ImageID]) Clear(galleryID uuid.UUID) command.Cmd[struct{}]

Clear returns the command to clear the [gallery.Stack]s of a *Gallery.

func (*Commands[StackID, ImageID]) ClearStack

func (c *Commands[StackID, ImageID]) ClearStack(galleryID uuid.UUID, stackID StackID) command.Cmd[StackID]

ClearStack returns the command to clear the variants of a gallery.Stack.

func (*Commands[StackID, ImageID]) Handle

func (c *Commands[StackID, ImageID]) Handle(
	ctx context.Context,
	newFunc func(uuid.UUID) handler.Aggregate,
	bus command.Bus,
	repo aggregate.Repository,
) (<-chan error, error)

Handle subscribes to gallery commands and executes them on the actual gallery aggregate that is returned by calling newFunc with the id of the gallery.

func (*Commands[StackID, ImageID]) Register

func (c *Commands[StackID, ImageID]) Register(r codec.Registerer)

Register calls RegisterCommands(r).

func (*Commands[StackID, ImageID]) RemoveStack

func (c *Commands[StackID, ImageID]) RemoveStack(galleryID uuid.UUID, stackID StackID) command.Cmd[removeStack[StackID]]

RemoveStack returns the command to remove a gallery.Stack from a *Gallery.

func (*Commands[StackID, ImageID]) RemoveVariant

func (c *Commands[StackID, ImageID]) RemoveVariant(galleryID uuid.UUID, stackID StackID, variantID ImageID) command.Cmd[removeVariant[StackID, ImageID]]

RemoveVariant returns the command to remove a [Variant] from a gallery.Stack in a *Gallery.

func (*Commands[StackID, ImageID]) ReplaceVariant

func (c *Commands[StackID, ImageID]) ReplaceVariant(galleryID uuid.UUID, stackID StackID, variant gallery.Image[ImageID]) command.Cmd[replaceVariant[StackID, ImageID]]

ReplaceVariant returns the command to replace a [Variant] in a gallery.Stack in a *Gallery.

func (*Commands[StackID, _]) Sort

func (c *Commands[StackID, _]) Sort(galleryID uuid.UUID, sorting []StackID) command.Cmd[[]StackID]

Sort returns the command to sort the [gallery.Stack]s in a *Gallery.

func (*Commands[StackID, ImageID]) TagStack

func (c *Commands[StackID, ImageID]) TagStack(galleryID uuid.UUID, stackID StackID, tags ...string) command.Cmd[tagStack[StackID]]

TagStack returns the command to add tags to a gallery.Stack in a *Gallery.

func (*Commands[StackID, ImageID]) UntagStack

func (c *Commands[StackID, ImageID]) UntagStack(galleryID uuid.UUID, stackID StackID, tags ...string) command.Cmd[untagStack[StackID]]

UntagStack returns the command to remove tags from a gallery.Stack in a *Gallery.

type Encoder

type Encoder struct {
	// contains filtered or unexported fields
}

Encoder encodes images of different content-types. It is safe for concurrent use. DefaultEncoder is an *Encoder with support for encoding "image/png", "image/jpeg", and "image/gif" content-types. The zero-value Encoder is ready-to-use.

var enc Encoder
enc.Register("image/png", png.Encode)

var buf bytes.Buffer
var img image.Image

err := enc.Encode(&buf, "image/png", img)
encoded := buf.Bytes()
var DefaultEncoder *Encoder

DefaultEncoder is an *Encoder with support for encoding "image/png", "image/jpeg", and "image/gif" content-types.

Encoders

func (*Encoder) Encode

func (enc *Encoder) Encode(w io.Writer, contentType string, img image.Image) error

Encode encodes the provided image.Image and writes the result to `w`, using registered encoder for the given content-type. If no encoder was registered for this content-type, an error that satisfies errors.Is(err, ErrMissingEncoder) is returned.

func (*Encoder) Register

func (enc *Encoder) Register(contentType string, encoder func(io.Writer, image.Image) error)

Register registers an encoder function for the given content-type.

type EncoderFunc

type EncoderFunc func(io.Writer, string, image.Image) error

EncoderFunc is a function that can be used as an Encoding.

func (EncoderFunc) Encode

func (encode EncoderFunc) Encode(w io.Writer, contentType string, img image.Image) error

Encode implements Encoding.

type Encoding

type Encoding interface {
	Encode(w io.Writer, contentType string, img image.Image) error
}

An Encoding encodes images of different content-types.

type Gallery[StackID, ImageID ID, T Target] struct {
	*gallery.Base[StackID, ImageID]
	// contains filtered or unexported fields
}

Gallery provides the core implementation for image galleries. An aggregate that embeds *Gallery implements a ready-to-use image gallery.

type MyGallery struct {
	*aggregate.Base
	*esgallery.Gallery
}

func NewGallery(id uuid.UUID) *MyGallery {
	g := &MyGallery{Base: aggregate.New("myapp.gallery", id)}
	g.Gallery = esgallery.New(g)
	return g
}

func New

func New[StackID, ImageID ID, T Target](target T) *Gallery[StackID, ImageID, T]

New returns a new *Gallery that applies events and commands to the provided target aggregate. Typically, the target aggregate should embed *Gallery and initialize it within its constructor.

type MyGallery struct {
	*aggregate.Base
	*esgallery.Gallery
}

func NewGallery(id uuid.UUID) *MyGallery {
	g := &MyGallery{Base: aggregate.New("myapp.gallery", id)}
	g.Gallery = esgallery.New(g)
	return g
}

func (*Gallery[StackID, ImageID, Target]) AddVariant

func (g *Gallery[StackID, ImageID, Target]) AddVariant(stackID StackID, variant gallery.Image[ImageID]) (gallery.Stack[StackID, ImageID], error)

AddVariant adds a variant to a gallery.Stack. If the gallery.Stack cannot be found in the gallery, an error that satisfies errors.Is(err, gallery.ErrStackNotFound) is returned. If the ID of the provided variant is empty (zero-value), an error that satisfies errors.Is(err, gallery.ErrEmptyID) is returned. If the ID of the variant already exists within the same gallery.Stack, an error that satisfies errors.Is(err, gallery.ErrDuplicateID) is returned.

func (*Gallery[StackID, ImageID, Target]) AddVariants added in v0.0.19

func (g *Gallery[StackID, ImageID, Target]) AddVariants(stackID StackID, variants []gallery.Image[ImageID]) (gallery.Stack[StackID, ImageID], error)

AddVariant adds multiple variants to a gallery.Stack. Read the documentation of g.AddVariant for more information.

func (*Gallery[StackID, ImageID, T]) Clear added in v0.0.12

func (g *Gallery[StackID, ImageID, T]) Clear()

func (*Gallery[StackID, ImageID, T]) ClearStack

func (g *Gallery[StackID, ImageID, T]) ClearStack(id StackID) (gallery.Stack[StackID, ImageID], error)

ClearStacks removes all variants from a gallery.Stack except the original.

func (*Gallery[StackID, ImageID, T]) MarkAsProcessed added in v0.0.27

func (g *Gallery[StackID, ImageID, T]) MarkAsProcessed(stackID StackID)

MarkAsProcessed marks a gallery.Stack as being processed by a post-processor.

func (*Gallery[StackID, ImageID, Target]) NewStack

func (g *Gallery[StackID, ImageID, Target]) NewStack(id StackID, img gallery.Image[ImageID]) (gallery.Stack[StackID, ImageID], error)

NewStack is the event-sourced variant of *gallery.Base.NewStack.

func (*Gallery[StackID, ImageID, Target]) NewVariant

func (g *Gallery[StackID, ImageID, Target]) NewVariant(stackID StackID, variantID ImageID, img image.Image) (gallery.Stack[StackID, ImageID], error)

NewVariant is the event-sourced variant of *gallery.Base.NewVariant.

func (*Gallery[StackID, ImageID, T]) ProcessedStacks added in v0.0.27

func (g *Gallery[StackID, ImageID, T]) ProcessedStacks() []StackID

ProcessedStacks returns ids of the stacks that have been processed by a post-processor.

func (*Gallery[StackID, ImageID, Target]) RemoveStack

func (g *Gallery[StackID, ImageID, Target]) RemoveStack(id StackID) (gallery.Stack[StackID, ImageID], error)

RemoveStack is the event-sourced variant of *gallery.Base.RemoveStack.

func (*Gallery[StackID, ImageID, Target]) RemoveVariant

func (g *Gallery[StackID, ImageID, Target]) RemoveVariant(stackID StackID, imageID ImageID) (gallery.Image[ImageID], error)

RemoveVariant is the event-sourced variant of *gallery.Base.RemoveVariant.

func (*Gallery[StackID, ImageID, Target]) ReplaceVariant

func (g *Gallery[StackID, ImageID, Target]) ReplaceVariant(stackID StackID, variant gallery.Image[ImageID]) (gallery.Stack[StackID, ImageID], error)

ReplaceVariant is the event-sourced variant of *gallery.Base.ReplaceVariant.

func (*Gallery[StackID, ImageID, Target]) Sort

func (g *Gallery[StackID, ImageID, Target]) Sort(sorting []StackID)

Sort is the event-sourced variant of *gallery.Base.Sort.

func (*Gallery[StackID, ImageID, Target]) Tag

func (g *Gallery[StackID, ImageID, Target]) Tag(stackID StackID, tags ...string) (gallery.Stack[StackID, ImageID], error)

Tag is the event-sourced variant of *gallery.Base.Tag.

func (*Gallery[StackID, ImageID, Target]) Target

func (g *Gallery[StackID, ImageID, Target]) Target() Target

Target returns the actual aggregate that embeds this Gallery.

func (*Gallery[StackID, ImageID, Target]) Untag

func (g *Gallery[StackID, ImageID, Target]) Untag(stackID StackID, tags ...string) (gallery.Stack[StackID, ImageID], error)

Untag is the event-sourced variant of *gallery.Base.Untag.

type ID

type ID = gallery.ID

ID is the type constraint for [gallery.Stack]s and [gallery.Image]s of a gallery.

type MemoryStorage

type MemoryStorage struct {
	// contains filtered or unexported fields
}

MemoryStorage is a thread-safe Storage that stores images in memory.

func (*MemoryStorage) Files

func (s *MemoryStorage) Files() map[string][]byte

Files returns all stored files as a mapping from paths to contents.

func (*MemoryStorage) Get

func (s *MemoryStorage) Get(_ context.Context, p string) (io.Reader, error)

Put implements Storage.

func (*MemoryStorage) Put

func (s *MemoryStorage) Put(_ context.Context, p string, contents io.Reader) (image.Storage, error)

Put implements Storage.

func (*MemoryStorage) SetRoot

func (s *MemoryStorage) SetRoot(root string)

SetRoot sets the root path of the MemoryStorage. The root path is prepended to all paths passed to Put and Get.

type PostProcessor

type PostProcessor[
	Gallery ProcessableGallery[StackID, ImageID],
	StackID, ImageID ID,
] struct {
	// contains filtered or unexported fields
}

PostProcessor is a post-processor for gallery images. Whenever a new gallery.Stack is added to a gallery, or whenever the original image of a gallery.Stack is replaced, the post-processor is triggered to post-process that gallery.Stack.

Example

This example makes use of [repository.Typed], which returns a aggregate.TypedRepository that provides a Fetch method that can be directly passed to NewPostProcessor.

type MyGallery struct { ... }
func NewGallery(id uuid.UUID) *MyGallery { return &MyGallery{ ... } }

var p *Processor
var bus event.Bus
var repo aggregate.Repository

galleries := repository.Typed(repo, NewGallery)
pp := NewPostProcessor(p, bus, galleries.Fetch)

func NewPostProcessor

func NewPostProcessor[
	Gallery ProcessableGallery[StackID, ImageID],
	StackID, ImageID ID,
](
	p *Processor[StackID, ImageID],
	bus event.Bus,
	fetchGallery func(context.Context, uuid.UUID) (Gallery, error),
	opts ...PostProcessorOption[Gallery, StackID, ImageID],
) *PostProcessor[Gallery, StackID, ImageID]

NewPostProcessor returns a new post-processor for gallery images. Read the documentation of PostProcessor for more information.

func (*PostProcessor[Gallery, StackID, ImageID]) Run

func (pp *PostProcessor[Gallery, StackID, ImageID]) Run(ctx context.Context, pipeline image.Pipeline, opts ...RunProcessorOption) (
	<-chan ProcessorResult[StackID, ImageID],
	<-chan error,
	error,
)

Run runs the post-processor in the background and returns a channel of results and a channel of errors. Processing stops when the provided Context is canceled. If the underlying event bus fails to subscribe to ProcessorTriggerEvents, nil channels and the event bus error are returned.

type PostProcessorOption

type PostProcessorOption[
	Gallery ProcessableGallery[StackID, ImageID],
	StackID, ImageID ID,
] func(*PostProcessor[Gallery, StackID, ImageID])

PostProcessorOption is an option for NewPostProcessor.

func WithAutoApply

func WithAutoApply[
	StackID, ImageID ID,
	Gallery ProcessableGallery[StackID, ImageID],
](autoApply bool, save func(context.Context, Gallery) error) PostProcessorOption[Gallery, StackID, ImageID]

WithAutoApply returns a PostProcessorOption that automatically applies [ProcessorResult]s to gallery aggregates. If the provided `save` function is non-nil, galleries will also be saved after applying the result.

type ProcessableGallery

type ProcessableGallery[StackID, ImageID ID] interface {
	pick.AggregateProvider

	// Stack returns the given [gallery.Stack].
	Stack(StackID) (gallery.Stack[StackID, ImageID], bool)

	// NewStack adds a new [gallery.Stack] to the gallery.
	NewStack(StackID, gallery.Image[ImageID]) (gallery.Stack[StackID, ImageID], error)

	// ClearStacks removes all variants from a [gallery.Stack] except the original.
	ClearStack(StackID) (gallery.Stack[StackID, ImageID], error)

	// ReplaceVariant replaces a variant of a [gallery.Stack].
	ReplaceVariant(StackID, gallery.Image[ImageID]) (gallery.Stack[StackID, ImageID], error)

	// AddVariant adds a new variant to a [gallery.Stack].
	AddVariant(StackID, gallery.Image[ImageID]) (gallery.Stack[StackID, ImageID], error)

	// Tag adds tags to a [gallery.Stack].
	Tag(StackID, ...string) (gallery.Stack[StackID, ImageID], error)

	// MarkAsProcessed marks a [gallery.Stack] as being processed by a post-processor.
	MarkAsProcessed(StackID)
}

ProcessableGallery is the type constraint for gallery aggregates that can be handled by [*Processor]s and [*Uploader]s.

type ProcessedImage

type ProcessedImage[ImageID ID] struct {
	Image     gallery.Image[ImageID]
	Processed image.Processed
}

ProcessedImage provides the built gallery.Image, and the processed image from the processing pipeline.

type Processor

type Processor[StackID, ImageID ID] struct {
	// contains filtered or unexported fields
}

Processor post-processes [gallery.Stack]s and uploads the processed images to (cloud) storage.

func NewProcessor

func NewProcessor[StackID, ImageID ID](
	enc Encoding,
	storage Storage,
	uploader *Uploader[StackID, ImageID],
	newVariantID func() ImageID,
) *Processor[StackID, ImageID]

NewProcessor returns a post-processor for gallery images.

func (*Processor[StackID, ImageID]) Process

func (p *Processor[StackID, ImageID]) Process(
	ctx context.Context,
	pipeline image.Pipeline,
	g ProcessableGallery[StackID, ImageID],
	stackID StackID,
) (ProcessorResult[StackID, ImageID], error)

Process post-processes the given gallery.Stack of the provided gallery ([StackProvider]). The returned ProcessorResult can be applied to (gallery) aggregates to actually add the processed images to a gallery. The provided image.Pipeline runs on the original image of the gallery.Stack.

The returned ProcessorResult can be applied to a gallery aggregate by calling ProcessorResult.Apply. Appropriate events will be raised to replace the original variant of the gallery.Stack, and/or to add new variants.

var gallery *Gallery
result, err := p.Process(context.TODO(), image.Pipeline{...}, gallery, stackID)
// handle err
err := result.Apply(gallery)

type ProcessorResult

type ProcessorResult[StackID, ImageID ID] struct {
	image.PipelineResult

	Gallery aggregate.Ref

	// Trigger is the event that triggered the processing. If the [*Processor]
	// was called manually, Trigger is nil.
	Trigger event.Event

	// StackID is the ID of processed [gallery.Stack].
	StackID StackID

	// Images are the processed images.
	Images []ProcessedImage[ImageID]

	// Runtime is the time it took to process the [gallery.Stack].
	Runtime time.Duration

	// Applied is set to true if the post-processor applied the result to the
	// gallery. This is the case if the [WithAutoApply] option is enabled.
	// Consider passing the [DiscardResults] option to [PostProcessor.Run] when
	// enabling [WithAutoApply], to avoid having to pull the results from the
	// returned channel.
	Applied bool

	// Saved is set to true if the post-processor saved the gallery after
	// applying the result to it. This is the case if a non-nil "save" function
	// was passed to [WithAutoApply]. Saved can only be true if Applied is true.
	Saved bool
}

ProcessorResult is the result post-processing a gallery.Stack.

func (ProcessorResult[StackID, ImageID]) Apply

func (r ProcessorResult[StackID, ImageID]) Apply(g ProcessableGallery[StackID, ImageID], opts ...ApplyResultOption) error

ApplyProcessorResult applies a ProcessorResult to a Gallery by raising the appropriate events.

type RunProcessorOption

type RunProcessorOption func(*runProcessorConfig)

RunProcessorOption is an option for *PostProcessor.Run.

func Debug added in v0.0.15

func Debug(debug bool) RunProcessorOption

Debug returns a RunProcessorOption that enables debug logs.

func DiscardResults

func DiscardResults(discard bool) RunProcessorOption

DiscardResults returns a RunProcessorOption that discards the [ProcessorResult]s instead of returning them in the result channel. Typically, you want to use this option in conjunction with WithAutoApply.

func FilterAggregates added in v0.0.18

func FilterAggregates(aggregates []string) RunProcessorOption

FilterAggregates returns a PostProcessorOption that checks if a received ProcessorTriggerEvents event belongs to the event stream of one of the provided aggregates. If the event does not belong to any of these aggregates, the post-processor will not be triggered for that event.

func FilterEvents added in v0.0.18

func FilterEvents(filter func(event.Event) bool) RunProcessorOption

FilterEvents returns a PostProcessorOption that calls the provided filter function when receiving a ProcessorTriggerEvents event. If the filter returns false, the post-processor will not be triggered for that event. When multiple filters are provided, all filters must return true for the post-processor to be triggered.

func Workers

func Workers(workers int) RunProcessorOption

Workers returns a RunProcessorOption that sets the number of workers for PostProcessor.Run. Defaults to 1.

type StackTaggedData

type StackTaggedData[StackID ID] struct {
	StackID StackID
	Tags    gallery.Tags
}

type StackUntaggedData

type StackUntaggedData[StackID ID] struct {
	StackID StackID
	Tags    gallery.Tags
}

type Storage

type Storage interface {
	// Put writes the contents of the image in r to the storage at the given
	// path and returns the storage location of the uploaded image.
	Put(ctx context.Context, path string, contents io.Reader) (image.Storage, error)

	// Get returns the contents of the image at the given storage path.
	Get(ctx context.Context, path string) (io.Reader, error)
}

Storage is the storage for gallery images.

type Target

Target is an event-sourced aggregate that acts as a gallery. The *Gallery provided by this package provides the core functionality for image galleries, and applies events and commands to a provided Target.

An aggregate must implement event.Registerer and command.Registerer to be used a Target.

type Uploader

type Uploader[StackID, ImageID ID] struct {
	// contains filtered or unexported fields
}

Uploader uploads gallery images to (cloud) storage. An Uploader can be passed to a *Processor to automatically upload processed images to (cloud) storage.

func NewUploader

func NewUploader[StackID, ImageID ID](storage Storage) *Uploader[StackID, ImageID]

NewUploader returns an *Uploader that uploads images to the provided Storage.

func (*Uploader[StackID, ImageID]) UploadNew

func (u *Uploader[StackID, ImageID]) UploadNew(
	ctx context.Context,
	g ProcessableGallery[StackID, ImageID],
	stackID StackID,
	imageID ImageID,
	r io.Reader,
	filename string,
) (gallery.Stack[StackID, ImageID], error)

UploadNew uploads a new image to the provided gallery and returns the newly created gallery.Stack.

The filesize and dimensions of the uploaded image are determined while uploading to storage, and set on the gallery.Image in the returned gallery.Stack. The Filename of the returned gallery.Image is set to the provided filename.

To upload a new variant of an existing gallery.Stack, call u.UploadVariant() instead.

func (*Uploader[StackID, ImageID]) UploadVariant

func (u *Uploader[StackID, ImageID]) UploadVariant(
	ctx context.Context,
	g ProcessableGallery[StackID, ImageID],
	stackID StackID,
	variantID ImageID,
	r io.Reader,
) (gallery.Image[ImageID], error)

UploadVariant writes the image in `r` to the underlying Storage and returns a gallery.Image that represents the uploaded image. The returned gallery.Image can be added to a *Gallery, either by calling *Gallery.AddVariant, or by applying a ProcessorResult to the gallery with [ApplyProcessorResult].

The provided StackID specifies the gallery.Stack the image should be added to. The provided ImageID is used as the ID of the returned gallery.Image. The storage path of the uploaded image is determined by the StackID, ImageID, and the ID of the provided gallery.

The filesize and dimensions of the uploaded image are determined while uploading to storage, and set on the returned gallery.Image. The Filename of the returned gallery.Image is set to the Filename of the original image of the gallery.Stack.

type VariantAddedData

type VariantAddedData[StackID, ImageID ID] struct {
	StackID StackID
	Variant gallery.Image[ImageID]
}

type VariantRemovedData

type VariantRemovedData[StackID, ImageID ID] struct {
	StackID StackID
	ImageID ImageID
}

type VariantReplacedData

type VariantReplacedData[StackID, ImageID ID] struct {
	StackID StackID
	Variant gallery.Image[ImageID]
}

type VariantsAddedData added in v0.0.19

type VariantsAddedData[StackID, ImageID ID] struct {
	StackID  StackID
	Variants []gallery.Image[ImageID]
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL