Artifex

package module
v0.46.5 Latest Latest
Warning

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

Go to latest
Published: May 2, 2024 License: MIT Imports: 24 Imported by: 0

README

Artifex

Features

  • Routes Group
  • Routes Parameter: /users/{user_id}/orders/{order_id}
  • Extendable: middleware support
  • Universal: message-driven architecture, stream processing ...etc, use it for whatever you need.
  • Adapter Lifecycle Management

Installation go package

go get -u github.com/KScaesar/Artifex

Why Create This Package

Simplifying Message Handling in Go.

I believe that most Go developers have used the Gin HTTP package, and my favorite part of it is the way Message HandleFunc are written.

This approach not only satisfies the Single Responsibility Principle (SRP) but also utilizes middleware design to enhance the code's extensibility, fulfilling the requirements of the Open-Closed Principle (OCP).

In everyday work, we not only handle HTTP messages but also utilize other backend common messaging methods such as Redis, RabbitMQ, WebSocket, SSE, and Kafka.

Unfortunately, I often encounter code that is difficult to maintain, written using basic switch-case or if-else statements, in my work.

In Go, these foundational open-source packages typically don't offer a built-in method to achieve HandleFunc design patterns.

Therefore, I create the message mux (multiplexer) based on generics, aiming to establish a message handling pattern similar to gin's HandleFunc.

Usage example

One example like the following:

Example

Go Playground

package main

var useLogger = Artifex.UseLogger(false, false)

func main() {
	Artifex.SetDefaultLogger(Artifex.NewLogger(false, Artifex.LogLevelDebug))

	routeDelimiter := "/"
	mux := Artifex.NewMux(routeDelimiter)

	use := Artifex.Use{Logger: useLogger}
	mux.ErrorHandler(use.PrintResult(nil))

	mux.Middleware(func(next Artifex.HandleFunc) Artifex.HandleFunc {
		return func(message *Artifex.Message, dep any) error {
			logger := useLogger(message, dep)
			logger.Info(">>>>>> recv %q <<<<<<", message.Subject)
			return next(message, dep)
		}
	})

	// Note:
	// Before registering handler, middleware must be defined;
	// otherwise, the handler won't be able to use middleware.
	mux.Middleware(use.Recover())

	// When a subject cannot be found, execute the 'Default'
	mux.DefaultHandler(use.PrintDetail())

	v1 := mux.Group("v1/").Middleware(HandleAuth().PreMiddleware())

	v1.Handler("Hello/{user}", Hello)

	db := make(map[string]any)
	v1.Handler("UpdatedProductPrice/{brand}", UpdatedProductPrice(db))

	// Endpoints:
	// [Artifex] subject=".*"                                f="main.DefaultHandler"
	// [Artifex] subject="v1/Hello/{user}"                   f="main.Hello"
	// [Artifex] subject="v1/UpdatedProductPrice/{brand}"    f="main.main.UpdatedProductPrice.func5"
	mux.Endpoints(func(subject, fn string) { fmt.Printf("[Artifex] subject=%-35q f=%q\n", subject, fn) })

	intervalSecond := 2
	Listen(mux, intervalSecond)
}

Advanced usage

Generate code cli is used to generate template code for message.go and adapter.go.

Modify the template content according to the requirements,
select PubSub, Publisher, or Subscriber as needed, and delete unused code.

go install github.com/KScaesar/Artifex/cmd/artifex@latest
artifex gen

or

artifex gen -dir {Path} -pkg {Package} -f {File} -s {Subject}
artifex -h

help: 
    artifex gen -dir  ./    -pkg  infra    -f  kafka -s  Topic
    artifex gen -dir {Path} -pkg {Package} -f {File} -s {Subject}

-dir  Generate code to dir
-f    File prefix name
-pkg  Package name
-s    Subject name

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrClosed          = NewCustomError(2001, "service has been closed")
	ErrNotFound        = NewCustomError(2100, "not found")
	ErrNotFoundSubject = NewCustomError(2101, "not found subject mux")
)

Functions

func AnyToString added in v0.44.0

func AnyToString(v any) string

func CtxWithLogger added in v0.44.0

func CtxWithLogger(ctx context.Context, dep any, v Logger) context.Context

func CtxWithPingPong added in v0.44.0

func CtxWithPingPong(ctx context.Context, v WaitPingPong) context.Context

func ErrorExtractCode

func ErrorExtractCode(err error) int

func ErrorJoin3rdParty

func ErrorJoin3rdParty(myErr error, Err3rd error) error

func ErrorJoin3rdPartyWithMsg

func ErrorJoin3rdPartyWithMsg(myErr error, Err3rd error, msg string, args ...any) error

func ErrorWrapWithMessage

func ErrorWrapWithMessage(myErr error, msg string, args ...any) error

func GenerateRandomCode

func GenerateRandomCode(length int) string

func GenerateUlid added in v0.31.0

func GenerateUlid() string

func LookupLogLevel

func LookupLogLevel(level LogLevel) string

func PutMessage added in v0.44.0

func PutMessage(message *Message)

func ReliableTask

func ReliableTask(task func() error, allowStop func() bool, retryMaxSecond int, fixup func() error) error

func SendPingWaitPong

func SendPingWaitPong(sendPingSeconds int, sendPing func() error, waitPong WaitPingPong, isStopped func() bool) error

func SetDefaultLogger

func SetDefaultLogger(l Logger)

func UseSkipMessage added in v0.43.0

func UseSkipMessage() func(message *Message, dep any) error

func WaitPingSendPong

func WaitPingSendPong(waitPingSeconds int, waitPing WaitPingPong, sendPong func() error, isStop func() bool) error

Types

type Adapter added in v0.16.0

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

func (*Adapter) Identifier added in v0.16.0

func (adp *Adapter) Identifier() string

func (*Adapter) IsStopped added in v0.27.0

func (adp *Adapter) IsStopped() bool

func (*Adapter) Listen added in v0.16.0

func (adp *Adapter) Listen() (err error)

func (*Adapter) Log added in v0.37.0

func (adp *Adapter) Log() Logger

func (*Adapter) OnDisconnect added in v0.46.0

func (adp *Adapter) OnDisconnect(terminates ...func(adp IAdapter))

func (*Adapter) RawInfra added in v0.43.0

func (adp *Adapter) RawInfra() any

func (*Adapter) RawSend added in v0.46.0

func (adp *Adapter) RawSend(messages ...*Message) error

func (*Adapter) Send added in v0.16.0

func (adp *Adapter) Send(messages ...*Message) error

func (*Adapter) SetLog added in v0.37.0

func (adp *Adapter) SetLog(logger Logger)

func (*Adapter) Stop added in v0.16.0

func (adp *Adapter) Stop() error

func (*Adapter) WaitStop added in v0.20.0

func (adp *Adapter) WaitStop() chan struct{}

type AdapterHub added in v0.7.0

type AdapterHub interface {
	Join(adapterId string, adp IAdapter) error
	RemoveOne(filter func(IAdapter) bool)
}

type AdapterOption added in v0.16.0

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

func NewAdapterOption added in v0.43.0

func NewAdapterOption() (opt *AdapterOption)

func (*AdapterOption) AdapterFixup added in v0.16.0

func (opt *AdapterOption) AdapterFixup(maxRetrySecond int, adapterFixup func(IAdapter) error) *AdapterOption

func (*AdapterOption) AdapterHub added in v0.36.0

func (opt *AdapterOption) AdapterHub(hub AdapterHub) *AdapterOption

func (*AdapterOption) AdapterRecv added in v0.16.0

func (opt *AdapterOption) AdapterRecv(adapterRecv func(logger Logger) (message *Message, err error)) *AdapterOption

func (*AdapterOption) AdapterSend added in v0.16.0

func (opt *AdapterOption) AdapterSend(adapterSend func(logger Logger, message *Message) error) *AdapterOption

func (*AdapterOption) AdapterStop added in v0.16.0

func (opt *AdapterOption) AdapterStop(adapterStop func(logger Logger) error) *AdapterOption

func (*AdapterOption) Build added in v0.33.0

func (opt *AdapterOption) Build() (adp IAdapter, err error)

func (*AdapterOption) DecorateAdapter added in v0.35.0

func (opt *AdapterOption) DecorateAdapter(wrap func(adapter IAdapter) (application IAdapter)) *AdapterOption

func (*AdapterOption) EgressMux added in v0.39.0

func (opt *AdapterOption) EgressMux(mux *Mux) *AdapterOption

func (*AdapterOption) Identifier added in v0.16.0

func (opt *AdapterOption) Identifier(identifier string) *AdapterOption

func (*AdapterOption) IngressMux added in v0.39.0

func (opt *AdapterOption) IngressMux(mux *Mux) *AdapterOption

func (*AdapterOption) Lifecycle added in v0.18.0

func (opt *AdapterOption) Lifecycle(setup func(life *Lifecycle)) *AdapterOption

func (*AdapterOption) Logger added in v0.37.0

func (opt *AdapterOption) Logger(logger Logger) *AdapterOption

func (*AdapterOption) RawInfra added in v0.43.0

func (opt *AdapterOption) RawInfra(infra any) *AdapterOption

func (*AdapterOption) SendPing added in v0.16.0

func (opt *AdapterOption) SendPing(sendPingSeconds int, waitPong WaitPingPong, sendPing func(IAdapter) error) *AdapterOption

SendPing

When SendPingWaitPong sends a ping message and waits for a corresponding pong message. SendPeriod = WaitSecond / 2

func (*AdapterOption) WaitPing added in v0.16.0

func (opt *AdapterOption) WaitPing(waitPingSeconds int, waitPing WaitPingPong, sendPong func(IAdapter) error) *AdapterOption

WaitPing

When WaitPingSendPong waits for a ping message and response a corresponding pong message. SendPeriod = WaitSecond

type Consumer added in v0.43.0

type Consumer interface {
	IAdapter
	Listen() (err error)
}

type CustomError

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

func NewCustomError

func NewCustomError(myCode int, title string) *CustomError

func (*CustomError) CustomError

func (c *CustomError) CustomError()

func (*CustomError) Error

func (c *CustomError) Error() string

func (*CustomError) MyCode

func (c *CustomError) MyCode() int

type HandleFunc

type HandleFunc func(message *Message, dep any) error
func Link(handler HandleFunc, middlewares ...Middleware) HandleFunc

func UseAdHocFunc added in v0.45.0

func UseAdHocFunc(AdHoc func(message *Message, dep any) error) HandleFunc

func UsePrintDetail added in v0.44.0

func UsePrintDetail() HandleFunc
func (h HandleFunc) Link(middlewares ...Middleware) HandleFunc

func (HandleFunc) PostMiddleware

func (h HandleFunc) PostMiddleware() Middleware

func (HandleFunc) PreMiddleware

func (h HandleFunc) PreMiddleware() Middleware

type Hub added in v0.9.0

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

func NewHub added in v0.9.0

func NewHub() *Hub

func (*Hub) Count added in v0.9.0

func (hub *Hub) Count(filter func(IAdapter) bool) int

Count If filter returns true, increase count

func (*Hub) DoAsync added in v0.9.0

func (hub *Hub) DoAsync(action func(IAdapter))

func (*Hub) DoSync added in v0.9.0

func (hub *Hub) DoSync(action func(IAdapter) (stop bool))

DoSync If action returns stop=true, stops the iteration.

func (*Hub) FindByKey added in v0.9.0

func (hub *Hub) FindByKey(key string) (adp IAdapter, found bool)

func (*Hub) FindMulti added in v0.15.0

func (hub *Hub) FindMulti(filter func(IAdapter) bool) (all []IAdapter, found bool)

If filter returns true, find target

func (*Hub) FindMultiByKey added in v0.15.0

func (hub *Hub) FindMultiByKey(keys []string) (all []IAdapter, found bool)

func (*Hub) FindOne added in v0.15.0

func (hub *Hub) FindOne(filter func(IAdapter) bool) (adp IAdapter, found bool)

If filter returns true, find target

func (*Hub) IsShutdown added in v0.39.0

func (hub *Hub) IsShutdown() bool

func (*Hub) Join added in v0.9.0

func (hub *Hub) Join(key string, adp IAdapter) error

func (*Hub) RemoveByKey added in v0.15.0

func (hub *Hub) RemoveByKey(key string)

func (*Hub) RemoveMulti added in v0.15.0

func (hub *Hub) RemoveMulti(filter func(IAdapter) bool)

If filter returns true, remove target

func (*Hub) RemoveMultiByKey added in v0.15.0

func (hub *Hub) RemoveMultiByKey(keys []string)

func (*Hub) RemoveOne added in v0.15.0

func (hub *Hub) RemoveOne(filter func(IAdapter) bool)

If filter returns true, remove target

func (*Hub) SetConcurrencyQty added in v0.9.0

func (hub *Hub) SetConcurrencyQty(concurrencyQty int)

SetConcurrencyQty concurrencyQty controls how many tasks can run simultaneously, preventing resource usage or avoid frequent context switches.

func (*Hub) Shutdown added in v0.37.4

func (hub *Hub) Shutdown()

func (*Hub) Total added in v0.9.0

func (hub *Hub) Total() int

func (*Hub) UpdateByOldKey added in v0.15.0

func (hub *Hub) UpdateByOldKey(oldKey string, update func(IAdapter) (freshKey string)) error

func (*Hub) WaitShutdown added in v0.39.0

func (hub *Hub) WaitShutdown() chan struct{}

type IAdapter added in v0.17.0

type IAdapter interface {
	Identifier() string
	Log() Logger
	SetLog(Logger)
	OnDisconnect(terminates ...func(adp IAdapter))
	Stop() error
	IsStopped() bool         // IsStopped is used for polling
	WaitStop() chan struct{} // WaitStop is used for event push
	RawInfra() any
}

type Lifecycle

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

Lifecycle define a management mechanism when init obj and terminate obj.

func (*Lifecycle) OnConnect added in v0.46.0

func (life *Lifecycle) OnConnect(inits ...func(adp IAdapter) error) *Lifecycle

func (*Lifecycle) OnDisconnect added in v0.46.0

func (life *Lifecycle) OnDisconnect(terminates ...func(adp IAdapter)) *Lifecycle

type LogLevel

type LogLevel uint8
const (
	LogLevelDebug LogLevel = iota + 1
	LogLevelInfo
	LogLevelWarn
	LogLevelError
	LogLevelFatal
)

type Logger

type Logger interface {
	Debug(format string, a ...any)
	Info(format string, a ...any)
	Warn(format string, a ...any)
	Error(format string, a ...any)
	Fatal(format string, a ...any)

	SetLogLevel(level LogLevel)
	LogLevel() LogLevel
	WithCallDepth(externalDepth uint) Logger
	WithKeyValue(key string, v any) Logger
}

func CtxGetLogger added in v0.44.0

func CtxGetLogger(ctx context.Context, dep any) Logger

func DefaultLogger

func DefaultLogger() Logger

func NewLogger

func NewLogger(printPath bool, level LogLevel) Logger

func NewWriterLogger added in v0.31.6

func NewWriterLogger(w io.Writer, printPath bool, level LogLevel) Logger

func SilentLogger

func SilentLogger() Logger

type Message added in v0.43.0

type Message struct {
	Subject string

	Bytes []byte
	Body  any

	Mutex sync.Mutex

	// RouteParam are used to capture values from subject.
	// These parameters represent resources or identifiers.
	//
	// Example:
	//
	//	define mux subject = "/users/{id}"
	//	send or recv subject = "/users/1017"
	//
	//	get route param:
	//		key : value => id : 1017
	RouteParam maputil.Data

	Metadata maputil.Data

	RawInfra any

	Ctx context.Context
	// contains filtered or unexported fields
}

func GetMessage added in v0.44.0

func GetMessage() *Message

func (*Message) Copy added in v0.45.0

func (msg *Message) Copy() *Message

func (*Message) MsgId added in v0.43.0

func (msg *Message) MsgId() string

func (*Message) SetMsgId added in v0.43.0

func (msg *Message) SetMsgId(msgId string)

func (*Message) UpdateContext added in v0.44.0

func (msg *Message) UpdateContext(updates ...func(ctx context.Context) context.Context) context.Context

type Middleware

type Middleware func(next HandleFunc) HandleFunc

func UseAsync added in v0.45.0

func UseAsync() Middleware

func UseExclude added in v0.44.0

func UseExclude(subjects []string) Middleware

func UseHowMuchTime added in v0.44.0

func UseHowMuchTime() Middleware

func UseInclude added in v0.44.0

func UseInclude(subjects []string) Middleware

func UseLogger added in v0.43.0

func UseLogger(withMsgId bool, safeConcurrency SafeConcurrencyKind) Middleware

func UsePrintResult added in v0.44.0

func UsePrintResult(isEgress bool, ignoreOkSubjects []string) Middleware

func UseRecover added in v0.44.0

func UseRecover() Middleware

func UseRetry added in v0.43.0

func UseRetry(retryMaxSecond int) Middleware
func (mw Middleware) Link(handler HandleFunc) HandleFunc

type Mux

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

Mux refers to a router or multiplexer, which can be used to handle different message. Itself is also a HandleFunc, but with added routing capabilities.

Message represents a high-level abstraction data structure containing metadata (e.g. header) + body

func NewMux

func NewMux(routeDelimiter string) *Mux

NewMux If routeDelimiter is an empty string, Message.RouteParam cannot be used. RouteDelimiter can only be set to a string of length 1. This parameter determines different parts of the Message.Subject.

func (*Mux) DefaultHandler added in v0.40.0

func (mux *Mux) DefaultHandler(h HandleFunc, mw ...Middleware) *Mux

DefaultHandler When a subject cannot be found, execute the 'Default'.

"The difference between 'Default' and 'NotFound' is that the 'Default' handler will utilize middleware, whereas 'NotFound' won't use middleware."

func (*Mux) EnableMessagePool added in v0.44.0

func (mux *Mux) EnableMessagePool() *Mux

func (*Mux) Endpoints added in v0.21.0

func (mux *Mux) Endpoints(action func(subject, handler string))

Endpoints get register handler function information

func (*Mux) ErrorHandler added in v0.40.0

func (mux *Mux) ErrorHandler(errHandlers ...Middleware) *Mux

func (*Mux) Group

func (mux *Mux) Group(groupName string) *Mux

func (*Mux) GroupByNumber added in v0.13.0

func (mux *Mux) GroupByNumber(groupName int) *Mux

func (*Mux) HandleMessage

func (mux *Mux) HandleMessage(message *Message, dependency any) (err error)

HandleMessage to handle various messages

- route parameter can nil

func (*Mux) Handler

func (mux *Mux) Handler(subject string, h HandleFunc, mw ...Middleware) *Mux

func (*Mux) HandlerByNumber added in v0.13.0

func (mux *Mux) HandlerByNumber(subject int, h HandleFunc, mw ...Middleware) *Mux

func (*Mux) Middleware

func (mux *Mux) Middleware(middlewares ...Middleware) *Mux

Middleware Before registering handler, middleware must be defined; otherwise, the handler won't be able to use middleware.

func (*Mux) NotFoundHandler added in v0.40.0

func (mux *Mux) NotFoundHandler(h HandleFunc) *Mux

NotFoundHandler When a subject cannot be found, execute the 'NotFound'.

"The difference between 'Default' and 'NotFound' is that the 'Default' handler will utilize middleware, whereas 'NotFound' won't use middleware."

func (*Mux) PostMiddleware

func (mux *Mux) PostMiddleware(handleFuncs ...HandleFunc) *Mux

func (*Mux) PreMiddleware

func (mux *Mux) PreMiddleware(handleFuncs ...HandleFunc) *Mux

func (*Mux) Transform

func (mux *Mux) Transform(transform HandleFunc) *Mux

Transform Originally, the message passed through the mux would only call 'getSubject' once. However, if there is a definition of Transform, when the message passes through the Transform function, 'getSubject' will be called again.

type Producer added in v0.43.0

type Producer interface {
	IAdapter
	Send(messages ...*Message) error
	RawSend(messages ...*Message) error
}

type Prosumer added in v0.43.0

type Prosumer interface {
	Producer
	Consumer
}

type SafeConcurrencyKind added in v0.45.0

type SafeConcurrencyKind int
const (
	SafeConcurrency_Skip SafeConcurrencyKind = iota
	SafeConcurrency_Mutex
	SafeConcurrency_Copy
)

type Shutdown

type Shutdown struct {
	Logger Logger
	// contains filtered or unexported fields
}

func NewShutdown added in v0.9.2

func NewShutdown() *Shutdown

func (*Shutdown) Notify added in v0.40.0

func (s *Shutdown) Notify(cause error)

func (*Shutdown) Serve added in v0.40.0

func (s *Shutdown) Serve(ctx context.Context)

func (*Shutdown) StopService added in v0.40.0

func (s *Shutdown) StopService(name string, action func() error) *Shutdown

func (*Shutdown) WaitFinish added in v0.40.0

func (s *Shutdown) WaitFinish() chan struct{}

type WaitPingPong added in v0.44.0

type WaitPingPong chan struct{}

func CtxGetPingPong added in v0.44.0

func CtxGetPingPong(ctx context.Context) WaitPingPong

func NewWaitPingPong added in v0.44.0

func NewWaitPingPong() WaitPingPong

func (WaitPingPong) Ack added in v0.44.0

func (wait WaitPingPong) Ack()

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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