kareless

package module
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Mar 17, 2024 License: GPL-3.0 Imports: 7 Imported by: 0

README

Kareless Coverage Badge

A pico-framework to glue building blocks of a long-running software together.

Why another dependency injector at all?

These are the reasons why I need another di, while there are great solutions like uber's fx in the wild:

  • Dependant (i.e. consumer) defines the expected type rather than the dependency itself; In other words, the dependant tries to cast the available dependency, which is resolved by name, to the desirable type and can use it in case of success.
  • Multi-tier settings storage is a first-class citizen.
  • Put restriction on cross-layer dependency to prevent making a mesh.
  • Reflection-free dependency resolution using string names and typecasts
  • Flexible dependency graph using settings to reduce unnecessary code changes and rebuilds

Usage

go get github.com/janstoon/toolbox/kareless
package main

import (
	"context"
	"log"

	"github.com/janstoon/toolbox/kareless"
	"github.com/janstoon/toolbox/kareless/std"
	"github.com/redis/go-redis/v9"
)

func main() {
	k := kareless.Compile().
		Feed( /* L1 Settings Source */).
		Feed(std.LocalEarlyLoadedSettingSource("conf", "/etc/janstoon")).
		Feed( /* L2 Settings Source */).
		Feed(std.MapSettingSource{
			"log.level":     5,
			"debug":         true,
			"redis.address": "redis://redis.janstun.com:6379/1",
		}).
		Feed( /* Default Settings Source as a Fallback */).
		Equip( /* Instruments as dependencies resolvable by name */).
		Equip(func(ss *kareless.Settings, ib *kareless.InstrumentBank) []kareless.InstrumentCatalogue {
			return []kareless.InstrumentCatalogue{
				{
					Names: []string{"redis", "infra/redis"},
					Builder: func(ss *kareless.Settings, ib *kareless.InstrumentBank) kareless.Instrument {
						oo, err := redis.ParseURL(ss.GetString("redis.address"))
						if err != nil {
							panic(err)
						}

						return redis.NewClient(oo)
					},
				},
			}
		}).
		Equip( /* Instruments as dependencies resolvable by name */).
		Install( /* Applications as dependencies available in a slice */).
		Install(
			func(ss *kareless.Settings, ib *kareless.InstrumentBank) kareless.Application {
				return appFoo{
					rc: kareless.ResolveInstrumentByType[*redis.Client](ib, "redis"),
				}
			},
			func(ss *kareless.Settings, ib *kareless.InstrumentBank) kareless.Application {
				return appBar{
					rc: kareless.ResolveInstrumentByType[*redis.Client](ib, "infra/redis"),
				}
			},
		).
		Connect( /* Drivers to drive application(s) */).
		Connect(func(ss *kareless.Settings, ib *kareless.InstrumentBank, apps []kareless.Application) kareless.Driver {
			type (
				appAccess = appFoo
				appOrdering  = appBar
			)

			adapter := struct {
				appAccess
				appOrdering
			}{}

			for _, v := range apps {
				switch app := v.(type) {
				case appFoo:
					adapter.appAccess = app

				case appBar:
					adapter.appOrdering = app
				}
			}

			return gateway{
				app: adapter,
			}
		}).
		AfterStart( /* Hooks to run after drivers started */).
		AfterStart(
			func(ctx context.Context, ss *kareless.Settings, ib *kareless.InstrumentBank, apps []kareless.Application) error {
				log.Println("System started...")

				return nil
			},
		)
	if err := k.Run(context.Background()); err != nil {
		panic(err)
	}
}

// ----------------------
//     Application(s)
// ----------------------

type appFoo struct {
	rc *redis.Client
}

func (a appFoo) Authenticate(ctx context.Context, token string) error {
	// Handle the use-case

	return nil
}

type appBar struct {
	rc *redis.Client
}

func (a appBar) SubmitOrder(ctx context.Context, details any) error {
	// Handle the use-case

	return nil
}

// ----------------------
//       Driver(s)
// ----------------------

type gwApp interface {
	accessApp
	orderingApp
}

type accessApp interface {
	Authenticate(ctx context.Context, token string) error
}

type orderingApp interface {
	SubmitOrder(ctx context.Context, details any) error
}

type gateway struct {
	app gwApp
}

func (d gateway) Run(ctx context.Context) error {
	// Start serving the service and driving the application

	return nil
}

Concepts

Setting Source

Instrument

Driver

Application

Kernel

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrAlreadyRegisteredInstrument = errors.New("instrument already registered")
	ErrUnresolvedDependency        = errors.New("dependency not resolved")
	ErrUnacceptableDependency      = errors.New("dependency not acceptable")
)

Functions

func InstrumentTesterByTypeAssertion

func InstrumentTesterByTypeAssertion[T any](v any) bool

func ResolveInstrumentByType

func ResolveInstrumentByType[T any](ib *InstrumentBank, name string) T

Types

type Application

type Application interface{}

type ApplicationConstructor

type ApplicationConstructor func(ss *Settings, ib *InstrumentBank) Application

type Driver

type Driver interface {
	Run(ctx context.Context) error
}

type DriverConstructor

type DriverConstructor func(ss *Settings, ib *InstrumentBank, apps []Application) Driver

type Hook

type Hook func(ctx context.Context, ss *Settings, ib *InstrumentBank, apps []Application) error

type Instrument

type Instrument interface{}

type InstrumentBank

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

func (*InstrumentBank) Resolve

func (ib *InstrumentBank) Resolve(name string, tester func(v any) bool) Instrument

type InstrumentCatalogue

type InstrumentCatalogue struct {
	Names   []string
	Builder InstrumentConstructor
}

type InstrumentConstructor

type InstrumentConstructor func(ss *Settings, ib *InstrumentBank) Instrument

type InstrumentInjector added in v0.6.0

type InstrumentInjector func(ss *Settings) []InstrumentCatalogue

type Kernel

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

func Compile

func Compile(oo ...Option) Kernel

func (Kernel) AfterStart

func (k Kernel) AfterStart(hh ...Hook) Kernel

func (Kernel) Connect

func (k Kernel) Connect(cc ...DriverConstructor) Kernel

Connect binds driver(s) to the Kernel in order to invoke use-cases on (drive) installed applications

func (Kernel) Equip

func (k Kernel) Equip(cc ...InstrumentInjector) Kernel

Equip plugs instruments which can get resolved by the instrument bank that is passed to unit constructors

func (Kernel) Feed

func (k Kernel) Feed(ss ...SettingSource) Kernel

Feed injects setting sources to be fed into configurable units like instruments, applications and drivers

func (Kernel) Install

func (k Kernel) Install(cc ...ApplicationConstructor) Kernel

Install appends installable applications to the list which become created on Run

func (Kernel) Run

func (k Kernel) Run(ctx context.Context) error

Run creates installed applications and connected drivers and waits until drivers and hooks are all finished running

type Option

type Option func(k Kernel) Kernel

func Connector

func Connector(cc ...DriverConstructor) Option

func Equipment

func Equipment(cc ...InstrumentInjector) Option

func Feeder

func Feeder(ss ...SettingSource) Option

func Installer

func Installer(cc ...ApplicationConstructor) Option

func PostHook

func PostHook(hh ...Hook) Option

type SettingSource

type SettingSource interface {
	Get(ctx context.Context, key string) (any, error)
}

type Settings

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

func (*Settings) Append added in v0.7.0

func (ss *Settings) Append(source SettingSource)

func (*Settings) Children

func (ss *Settings) Children(key string) []string

func (*Settings) GetBool

func (ss *Settings) GetBool(key string) bool

func (*Settings) GetByte

func (ss *Settings) GetByte(key string) byte

func (*Settings) GetDuration added in v0.7.1

func (ss *Settings) GetDuration(key string) time.Duration

func (*Settings) GetInt

func (ss *Settings) GetInt(key string) int

func (*Settings) GetInt64

func (ss *Settings) GetInt64(key string) int64

func (*Settings) GetString

func (ss *Settings) GetString(key string) string

func (*Settings) GetStringSlice added in v0.5.0

func (ss *Settings) GetStringSlice(key string) []string

func (*Settings) Prepend added in v0.7.0

func (ss *Settings) Prepend(source SettingSource)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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