usecases

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 27, 2025 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package usecases contains the core logic of the application and interfaces that exposes its requirements. This reverses dependencies by making specialized code depend on the core (DIP + clean architecture model).

Index

Constants

This section is empty.

Variables

View Source
var (

	// ErrStatusCancelled The operation was cancelled, typically by the caller.
	ErrStatusCancelled = errors.New("operation cancelled")

	// ErrStatusUnknown Unknown error. For example, this error may be returned when
	// a Status value received from another address space belongs to an error space
	// that is not known in this address space. Also errors raised by APIs that do
	// not return enough error information may be converted to this error.
	ErrStatusUnknown = errors.New("unknown error")

	// ErrStatusInvalidArgument The client specified an invalid argument. Note that
	// this differs from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments
	// that are problematic regardless of the state of the system (e.g., a malformed
	// file name).
	ErrStatusInvalidArgument = errors.New("invalid argument")

	// ErrStatusDeadlineExceeded The deadline expired before the operation could
	// complete. For operations that change the state of the system, this error may
	// be returned even if the operation has completed successfully. For example, a
	// successful response from a server could have been delayed long enough for the
	// deadline to expire.
	ErrStatusDeadlineExceeded = errors.New("deadline exceeded")

	// ErrStatusNotFound Some requested entity (e.g., file or directory) was not
	// found. Note to server developers: if a request is denied for an entire
	// class of users, such as gradual feature rollout or undocumented allowlist,
	// NOT_FOUND may be used. If a request is denied for some users within a class
	// of users, such as user-based access control, PERMISSION_DENIED must be used.
	ErrStatusNotFound = errors.New("not found")

	// ErrStatusAlreadyExists The entity that a client attempted to create (e.g.,
	// file or directory) already exists.
	ErrStatusAlreadyExists = errors.New("already exists")

	// ErrStatusPermissionDenied The caller does not have permission to execute
	// the specified operation. PERMISSION_DENIED must not be used for rejections
	// caused by exhausting some resource (use RESOURCE_EXHAUSTED instead for those
	// errors). PERMISSION_DENIED must not be used if the caller can not be identified
	// (use UNAUTHENTICATED instead for those errors). This error code does not
	// imply the request is valid or the requested entity exists or satisfies other
	// pre-conditions.
	ErrStatusPermissionDenied = errors.New("permission denied")

	// ErrStatusResourceExhausted Some resource has been exhausted, perhaps a
	// per-user quota, or perhaps the entire file system is out of space.
	ErrStatusResourceExhausted = errors.New("resource exhausted")

	// ErrStatusFailedPrecondition The operation was rejected because the system
	// is not in a state required for the operation’s execution. For example, the
	// directory to be deleted is non-empty, an rmdir operation is applied to a
	// non-directory, etc. Service implementors can use the following guidelines
	// to decide between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE: (a) Use
	// UNAVAILABLE if the client can retry just the failing call. (b) Use ABORTED
	// if the client should retry at a higher level (e.g., when a client-specified
	// test-and-set fails, indicating the client should restart a read-modify-write
	// sequence). (c) Use FAILED_PRECONDITION if the client should not retry until the
	// system state has been explicitly fixed. E.g., if an “rmdir” fails because the
	// directory is non-empty, FAILED_PRECONDITION should be returned since the client
	// should not retry unless the files are deleted from the directory.
	ErrStatusFailedPrecondition = errors.New("failed precondition")

	// ErrStatusAborted The operation was aborted, typically due to a concurrency
	// issue such as a sequencer check failure or transaction abort. See the guidelines
	// above for deciding between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE.
	ErrStatusAborted = errors.New("aborted")

	// ErrStatusOutOfRange The operation was attempted past the valid range.
	// E.g., seeking or reading past end-of-file. Unlike INVALID_ARGUMENT, this error
	// indicates a problem that may be fixed if the system state changes. For example,
	// a 32-bit file system will generate INVALID_ARGUMENT if asked to read at an
	// offset that is not in the range [0,2^32-1], but it will generate OUT_OF_RANGE
	// if asked to read from an offset past the current file size. There is a fair
	// bit of overlap between FAILED_PRECONDITION and OUT_OF_RANGE. We recommend using
	// OUT_OF_RANGE (the more specific error) when it applies so that callers who are
	// iterating through a space can easily look for an OUT_OF_RANGE error to detect
	// when they are done.
	ErrStatusOutOfRange = errors.New("out of range")

	// ErrStatusUnimplemented The operation is not implemented or is not supported/
	// enabled in this service.
	ErrStatusUnimplemented = errors.New("unimplemented")

	// ErrStatusInternal Internal errors. This means that some invariants expected
	// by the underlying system have been broken. This error code is reserved for
	// serious errors.
	ErrStatusInternal = errors.New("internal")

	// ErrStatusUnavailable The service is currently unavailable. This is most
	// likely a transient condition, which can be corrected by retrying with a backoff.
	// Note that it is not always safe to retry non-idempotent operations.
	ErrStatusUnavailable = errors.New("unavailable")

	// ErrStatusDataLoss Unrecoverable data loss or corruption.
	ErrStatusDataLoss = errors.New("data loss")

	// ErrStatusUnauthenticated The request does not have valid authentication
	// credentials for the operation.
	ErrStatusUnauthenticated = errors.New("unauthenticated")
)

TODO refactor errors, those feel quite bland

Functions

func ErrorFromHTTPStatus added in v0.3.0

func ErrorFromHTTPStatus(code int) error

ErrorFromHTTPStatus maps HTTP status codes to use-case errors.

Codes below 400 return nil as they're not errors in essence; callers must handle such cases directly, e.g. whether to follow a 3xx redirection or error is implementation-dependant.

func ErrorIn added in v0.3.0

func ErrorIn(err error, targets ...error) bool

ErrorIn checks if an error matches any of the target errors. It uses errors.Is to check each target in order. Returns true if err matches any target, false otherwise.

func ErrorJoinIf added in v0.3.0

func ErrorJoinIf(status, target error) error

ErrorJoinIf joins errors if the target error is not nil. Otherwise it returns nil.

Types

type Cache added in v0.3.0

type Cache interface {
	io.Closer

	GetString(ctx context.Context, key string) (string, error)
	SetString(ctx context.Context, key, value string, options ...CacheOption) error
}

Cache is a solution for fast storage and retrieval of ephemeral data

type CacheOption added in v0.3.0

type CacheOption interface {
	Apply(params *CacheOptions)
}

CacheOption provides a method to apply changes to an existing set of cache options.

func WithTTL added in v0.3.0

func WithTTL(duration time.Duration) CacheOption

WithTTL defines a time-to-live (TTL) for a cache entry.

type CacheOptionFn added in v0.3.0

type CacheOptionFn func(params *CacheOptions)

CacheOptionFn applies changes to existing cache parameters.

func (CacheOptionFn) Apply added in v0.3.0

func (fn CacheOptionFn) Apply(params *CacheOptions)

Apply changes cache parameters by applying itself.

type CacheOptions added in v0.3.0

type CacheOptions struct {
	TTL time.Duration
}

CacheOptions contains optional parameters to use when setting cache entries.

func NewCacheOptions added in v0.3.0

func NewCacheOptions(options ...CacheOption) *CacheOptions

NewCacheOptions creates a default set of parameters and applies all provided option in order.

type Doer added in v0.3.0

type Doer interface {
	Do(req *http.Request) (*http.Response, error)
}

Doer clients support execution of HTTP requests.

type Getter added in v0.2.0

type Getter interface {
	Get(ctx context.Context, uri string) ([]byte, error)
}

Getter supports fetching data from a given URI. It is client-dependant which URI components they support and for what.

type GetterFn added in v0.3.0

type GetterFn func(ctx context.Context, uri string) ([]byte, error)

GetterFn retrieves raw bytes from a given URI.

func FSGetter added in v0.3.0

func FSGetter(root fs.FS) GetterFn

FSGetter wraps a filesystem handler as a Getter.

func HTTPGetter added in v0.3.0

func HTTPGetter(doer Doer) GetterFn

HTTPGetter converts a Doer to a Getter. It considers only status code 200 OK as successful; any other codes will result in an error.

func (GetterFn) Get added in v0.3.0

func (fn GetterFn) Get(ctx context.Context, uri string) ([]byte, error)

Get retrieves raw bytes from a given URI.

type Logger added in v0.3.0

type Logger interface {
	Error(err error, msg string, keysAndValues ...any)
	Info(msg string, keysAndValues ...any)
}

Logger provides methods to emit informational and error messages. A simple logger will print former calls to stdout and latter ones to stderr.

TODO move this interface to gotell

type MediaList added in v0.3.0

type MediaList struct {
	Tracker Tracker
	Source  Source
	Store   Store
}

MediaList handles both a tracker to fetch user data and a mapper that can transform the media IDs from the tracker to another service

func (*MediaList) Close added in v0.3.0

func (lister *MediaList) Close() error

Close closes both the Tracker and Mapper

func (*MediaList) Generate added in v0.3.0

func (lister *MediaList) Generate(ctx context.Context, name string) (entities.CustomList, error)

Generate fetches the user media list from the Tracker and transform the IDs found to the target service through the Mapper

func (*MediaList) GetUserID added in v0.3.0

func (lister *MediaList) GetUserID(ctx context.Context, name string) (string, error)

GetUserID searches the Tracker for the user ID by their name/handle

func (*MediaList) MapIDs added in v0.3.0

func (lister *MediaList) MapIDs(
	ctx context.Context,
	ids []entities.SourceID,
) ([]entities.TargetID, error)

MapIDs converts IDs between a source tracker and a target reference. Returns all IDs that were found, or an empty slice if no matches were found.

func (*MediaList) Refresh added in v0.3.0

func (lister *MediaList) Refresh(ctx context.Context, client Getter) error

Refresh requests the Mapper to update its mapping definitions

type MediaLister added in v0.2.0

type MediaLister interface {
	io.Closer

	// Generate fetches the user media list from the Tracker and transform the IDs
	// found to the target service through the Mapper
	Generate(ctx context.Context, name string) (entities.CustomList, error)

	// GetUserID searches the Tracker for the user ID by their name/handle
	GetUserID(ctx context.Context, name string) (string, error)

	// MapIDs matches media IDs between two services
	MapIDs(ctx context.Context, ids []entities.SourceID) ([]entities.TargetID, error)

	// Refresh requests the Mapper to update its mapping definitions
	Refresh(ctx context.Context, client Getter) error
}

MediaLister converts media IDs between services and generates Sonarr custom list results. It handles providers, trackers and stores to fetch the data required for such conversions.

type Metadata added in v0.3.0

type Metadata interface {
	GetSourceID() string
	GetTargetID() string
	Valid() bool
}

Metadata represents any data that contains both the source Tracker media ID and the target service media ID

type Source added in v0.3.0

type Source interface {
	fmt.Stringer

	Fetch(ctx context.Context, client Getter) ([]Metadata, error)
}

Source is a data origin that provides metadata for mapping media IDs

type Store added in v0.3.0

type Store interface {
	io.Closer

	GetMedia(ctx context.Context, id string) (*entities.Media, error)
	GetMediaBulk(ctx context.Context, ids []string) ([]*entities.Media, error)
	PutMedia(ctx context.Context, media *entities.Media) error
	PutMediaBulk(ctx context.Context, medias []*entities.Media) error
}

Store handles the persistent storage and retrieval of media mapping data

type Tracker

type Tracker interface {
	io.Closer

	GetUserID(ctx context.Context, name string) (string, error)
	GetMediaListIDs(ctx context.Context, userID string) ([]entities.SourceID, error)
}

Tracker provides access to user metadata such as ID and media list from an upstream media tracking service

Jump to

Keyboard shortcuts

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