项目作者: gookit

项目描述 :
? Lightweight event manager and dispatcher implements by Go. Go实现的轻量级的事件管理、调度程序库, 支持设置监听器的优先级, 支持根据事件名称来进行一组事件的监听
高级语言: Go
项目地址: git://github.com/gookit/event.git


Event

GitHub go.mod Go version
GoDoc
Actions Status
Coverage Status
Go Report Card

Lightweight event management, dispatch tool library implemented by Go

  • Support for custom definition event objects
  • Support for adding multiple listeners to an event
  • Support setting the priority of the event listener, the higher the priority, the first to trigger
  • Support for a set of event listeners based on the event name prefix PREFIX.*.
    • ModeSimple(default) - app.* event listen, trigger app.run app.end, Both will fire the app.* listener
  • New match mode: ModePath
    • * Only match a segment of characters that are not ., allowing for finer monitoring and matching
    • ** matches any number of characters and can only be used at the beginning or end
  • Support for using the wildcard * to listen for triggers for all events
  • Support async trigger event by go channel consumers. use Async(), FireAsync()
  • Complete unit testing, unit coverage > 95%

中文说明

中文说明请看 README.zh-CN

GoDoc

Install

  1. go get github.com/gookit/event

Main method

  • On/Listen(name string, listener Listener, priority ...int) Register event listener
  • Subscribe/AddSubscriber(sbr Subscriber) Subscribe to support registration of multiple event listeners
  • Trigger/Fire(name string, params M) (error, Event) Trigger event by name and params
  • MustTrigger/MustFire(name string, params M) Event Trigger event, there will be panic if there is an error
  • FireEvent(e Event) (err error) Trigger an event based on a given event instance
  • FireBatch(es ...interface{}) (ers []error) Trigger multiple events at once
  • Async/FireC(name string, params M) Push event to chan, asynchronous consumption processing
  • FireAsync(e Event) Push event to chan, asynchronous consumption processing
  • AsyncFire(e Event) Async fire event by ‘go’ keywords

Quick start

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/gookit/event"
  5. )
  6. func main() {
  7. // Register event listener
  8. event.On("evt1", event.ListenerFunc(func(e event.Event) error {
  9. fmt.Printf("handle event: %s\n", e.Name())
  10. return nil
  11. }), event.Normal)
  12. // Register multiple listeners
  13. event.On("evt1", event.ListenerFunc(func(e event.Event) error {
  14. fmt.Printf("handle event: %s\n", e.Name())
  15. return nil
  16. }), event.High)
  17. // ... ...
  18. // Trigger event
  19. // Note: The second listener has a higher priority, so it will be executed first.
  20. event.MustFire("evt1", event.M{"arg0": "val0", "arg1": "val1"})
  21. }

Note: The second listener has a higher priority, so it will be executed first.

Using the wildcard

Match mode ModePath

Register event listener and name end with wildcard *:

  1. func main() {
  2. dbListener1 := event.ListenerFunc(func(e event.Event) error {
  3. fmt.Printf("handle event: %s\n", e.Name())
  4. return nil
  5. })
  6. event.On("app.db.*", dbListener1, event.Normal)
  7. }

Trigger events on other logic:

  1. func doCreate() {
  2. // do something ...
  3. // Trigger event
  4. event.MustFire("app.db.create", event.M{"arg0": "val0", "arg1": "val1"})
  5. }
  6. func doUpdate() {
  7. // do something ...
  8. // Trigger event
  9. event.MustFire("app.db.update", event.M{"arg0": "val0"})
  10. }

Like the above, triggering the app.db.create app.db.update event
will trigger the execution of the dbListener1 listener.

Match mode ModePath

ModePath It is a new pattern of v1.1.0, and the wildcard * matching logic has been adjusted:

  • * Only match a segment of characters that are not ., allowing for finer monitoring and matching
  • ** matches any number of characters and can only be used at the beginning or end
  1. em := event.NewManager("test", event.UsePathMode)
  2. // register listener
  3. em.On("app.**", appListener)
  4. em.On("app.db.*", dbListener)
  5. em.On("app.*.create", createListener)
  6. em.On("app.*.update", updateListener)
  7. // ... ...
  8. // fire event
  9. // TIP: will trigger appListener, dbListener, createListener
  10. em.Fire("app.db.create", event.M{"arg0": "val0", "arg1": "val1"})

Async fire events

Use chan fire events

You can use the Async/FireC/FireAsync method to trigger events, and the events will be written to chan for asynchronous consumption.
You can use CloseWait() to close the chan and wait for all events to be consumed.

Added option configuration:

  • ChannelSize Set buffer size for chan
  • ConsumerNum Set how many coroutines to start to consume events
  1. func main() {
  2. // Note: close event chan on program exit
  3. defer event.CloseWait()
  4. // defer event.Close()
  5. // register event listener
  6. event.On("app.evt1", event.ListenerFunc(func(e event.Event) error {
  7. fmt.Printf("handle event: %s\n", e.Name())
  8. return nil
  9. }), event.Normal)
  10. event.On("app.evt1", event.ListenerFunc(func(e event.Event) error {
  11. fmt.Printf("handle event: %s\n", e.Name())
  12. return nil
  13. }), event.High)
  14. // ... ...
  15. // Asynchronous consumption of events
  16. event.FireC("app.evt1", event.M{"arg0": "val0", "arg1": "val1"})
  17. }

Note: The event chan should be closed when the program exits.
You can use the following method:

  • event.Close() Close chan and no longer accept new events
  • event.CloseWait() Close chan and wait for all event processing to complete

Write event listeners

Using anonymous functions

You can use anonymous function for quick write an event lister.

  1. package mypgk
  2. import (
  3. "fmt"
  4. "github.com/gookit/event"
  5. )
  6. var fnHandler = func(e event.Event) error {
  7. fmt.Printf("handle event: %s\n", e.Name())
  8. return nil
  9. }
  10. func Run() {
  11. // register
  12. event.On("evt1", event.ListenerFunc(fnHandler), event.High)
  13. }

Using the structure method

You can use struct write an event lister, and it should implementation interface event.Listener.

interface:

  1. // Listener interface
  2. type Listener interface {
  3. Handle(e Event) error
  4. }

example:

Implementation interface event.Listener

  1. package mypgk
  2. import "github.com/gookit/event"
  3. type MyListener struct {
  4. // userData string
  5. }
  6. func (l *MyListener) Handle(e event.Event) error {
  7. e.Set("result", "OK")
  8. return nil
  9. }

Register multiple event listeners

Can implementation interface event.Subscriber for register
multiple event listeners at once.

interface:

  1. // Subscriber event subscriber interface.
  2. // you can register multi event listeners in a struct func.
  3. type Subscriber interface {
  4. // SubscribedEvents register event listeners
  5. // key: is event name
  6. // value: can be Listener or ListenerItem interface
  7. SubscribedEvents() map[string]interface{}
  8. }

Example

Implementation interface event.Subscriber

  1. package mypgk
  2. import (
  3. "fmt"
  4. "github.com/gookit/event"
  5. )
  6. type MySubscriber struct {
  7. // ooo
  8. }
  9. func (s *MySubscriber) SubscribedEvents() map[string]interface{} {
  10. return map[string]interface{}{
  11. "e1": event.ListenerFunc(s.e1Handler),
  12. "e2": event.ListenerItem{
  13. Priority: event.AboveNormal,
  14. Listener: event.ListenerFunc(func(e Event) error {
  15. return fmt.Errorf("an error")
  16. }),
  17. },
  18. "e3": &MyListener{},
  19. }
  20. }
  21. func (s *MySubscriber) e1Handler(e event.Event) error {
  22. e.Set("e1-key", "val1")
  23. return nil
  24. }

Write custom events

If you want to customize the event object or define some fixed event information in advance,
you can implement the event.Event interface.

interface:

  1. // Event interface
  2. type Event interface {
  3. Name() string
  4. // Target() interface{}
  5. Get(key string) interface{}
  6. Add(key string, val interface{})
  7. Set(key string, val interface{})
  8. Data() map[string]interface{}
  9. SetData(M) Event
  10. Abort(bool)
  11. IsAborted() bool
  12. }

examples:

  1. package mypgk
  2. import "github.com/gookit/event"
  3. type MyEvent struct {
  4. event.BasicEvent
  5. customData string
  6. }
  7. func (e *MyEvent) CustomData() string {
  8. return e.customData
  9. }

Usage:

  1. e := &MyEvent{customData: "hello"}
  2. e.SetName("e1")
  3. event.AddEvent(e)
  4. // add listener
  5. event.On("e1", event.ListenerFunc(func(e event.Event) error {
  6. fmt.Printf("custom Data: %s\n", e.(*MyEvent).CustomData())
  7. return nil
  8. }))
  9. // trigger
  10. event.Fire("e1", nil)
  11. // OR
  12. // event.FireEvent(e)

Note: is used to add pre-defined public event information, which is added in the initialization phase, so it is not locked.
Event dynamically created in business can be directly triggered by FireEvent()

Gookit packages

  • gookit/ini Go config management, use INI files
  • gookit/rux Simple and fast request router for golang HTTP
  • gookit/gcli build CLI application, tool library, running CLI commands
  • gookit/slog Lightweight, extensible, configurable logging library written in Go
  • gookit/event Lightweight event manager and dispatcher implements by Go
  • gookit/cache Generic cache use and cache manager for golang. support File, Memory, Redis, Memcached.
  • gookit/config Go config management. support JSON, YAML, TOML, INI, HCL, ENV and Flags
  • gookit/color A command-line color library with true color support, universal API methods and Windows support
  • gookit/filter Provide filtering, sanitizing, and conversion of golang data
  • gookit/validate Use for data validation and filtering. support Map, Struct, Form data
  • gookit/goutil Some utils for the Go: string, array/slice, map, format, cli, env, filesystem, test and more
  • More, please see https://github.com/gookit

LICENSE

MIT