DEV Community

Cover image for Lightweight event management, dispatch tool library implemented by Go
Inhere
Inhere

Posted on

Lightweight event management, dispatch tool library implemented by Go

event - Lightweight event management, dispatch tool library implemented by Go

  • Support for custom definition event objects
  • Support for adding multiple listeners to an event
  • Supports setting the priority of the event listener. The higher the priority, the higher the trigger.
  • Support for a set of event listeners based on the event name prefix PREFIX.*.
    • add app.* event listen, trigger app.run app.end, Both will trigger the app.* event at the same time
  • Support for using the wildcard * to listen for triggers for all events
  • Complete unit testing, unit coverage > 95%

Repo and doc

Install

go install github.com/gookit/event
Enter fullscreen mode Exit fullscreen mode

Quick start

package main

import (
    "fmt"

    "github.com/gookit/event"
)

func main() {
    // Register event listener
    event.On("evt1", event.ListenerFunc(func(e event.Event) error {
        fmt.Printf("handle event: %s\n", e.Name())
        return nil
    }), event.Normal)

    // Register multiple listeners
    event.On("evt1", event.ListenerFunc(func(e event.Event) error {
        fmt.Printf("handle event: %s\n", e.Name())
        return nil
    }), event.High)

    // ... ...

    // Trigger event
    // Note: The second listener has a higher priority, so it will be executed first.
    event.MustFire("evt1", event.M{"arg0": "val0", "arg1": "val1"})
}
Enter fullscreen mode Exit fullscreen mode

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

Using the wildcard

Register event listener and name end with wildcard *:

func main() {
    dbListener1 := event.ListenerFunc(func(e event.Event) error {
        fmt.Printf("handle event: %s\n", e.Name())
        return nil
    })

    event.On("app.db.*", dbListener1, event.Normal)
}
Enter fullscreen mode Exit fullscreen mode

Trigger events on other logic:

func doCreate() {
    // do something ...
    // Trigger event
    event.MustFire("app.db.create", event.M{"arg0": "val0", "arg1": "val1"})
}

func doUpdate() {
    // do something ...
    // Trigger event
    event.MustFire("app.db.update", event.M{"arg0": "val0"})
}
Enter fullscreen mode Exit fullscreen mode

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

Write event listeners

Using anonymous functions

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

package mypgk

import (
    "fmt"

    "github.com/gookit/event"
)

var fnHandler = func(e event.Event) error {
    fmt.Printf("handle event: %s\n", e.Name())
    return nil
}

func Run() {
    // register
    event.On("evt1", event.ListenerFunc(fnHandler), event.High)
}
Enter fullscreen mode Exit fullscreen mode

Using the structure method

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

interface:

// Listener interface
type Listener interface {
    Handle(e Event) error
}
Enter fullscreen mode Exit fullscreen mode

example:

Implementation interface event.Listener

package mypgk

import "github.com/gookit/event"

type MyListener struct {
    // userData string
}

func (l *MyListener) Handle(e event.Event) error {
    e.Set("result", "OK")
    return nil
}
Enter fullscreen mode Exit fullscreen mode

Register multiple event listeners

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

interface:

// Subscriber event subscriber interface.
// you can register multi event listeners in a struct func.
type Subscriber interface {
    // SubscribedEvents register event listeners
    // key: is event name
    // value: can be Listener or ListenerItem interface
    SubscribedEvents() map[string]interface{}
}
Enter fullscreen mode Exit fullscreen mode

example

Implementation interface event.Subscriber

package mypgk

import (
    "fmt"

    "github.com/gookit/event"
)

type MySubscriber struct {
    // ooo
}

func (s *MySubscriber) SubscribedEvents() map[string]interface{} {
    return map[string]interface{}{
        "e1": event.ListenerFunc(s.e1Handler),
        "e2": event.ListenerItem{
            Priority: event.AboveNormal,
            Listener: event.ListenerFunc(func(e Event) error {
                return fmt.Errorf("an error")
            }),
        },
        "e3": &MyListener{},
    }
}

func (s *MySubscriber) e1Handler(e event.Event) error {
    e.Set("e1-key", "val1")
    return nil
}
Enter fullscreen mode Exit fullscreen mode

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:

// Event interface
type Event interface {
    Name() string
    // Target() interface{}
    Get(key string) interface{}
    Add(key string, val interface{})
    Set(key string, val interface{})
    Data() map[string]interface{}
    SetData(M) Event
    Abort(bool)
    IsAborted() bool
}
Enter fullscreen mode Exit fullscreen mode

examples:

package mypgk

import "github.com/gookit/event"

type MyEvent struct {
    event.BasicEvent
    customData string
}

func (e *MyEvent) CustomData() string {
    return e.customData
}
Enter fullscreen mode Exit fullscreen mode

Usage:

e := &MyEvent{customData: "hello"}
e.SetName("e1")
event.AddEvent(e)

// add listener
event.On("e1", event.ListenerFunc(func(e event.Event) error {
    fmt.Printf("custom Data: %s\n", e.(*MyEvent).CustomData())
    return nil
}))

// trigger
event.Fire("e1", nil)
// OR
// event.FireEvent(e)
Enter fullscreen mode Exit fullscreen mode

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
  • AsyncFire(e Event) Async fire event by 'go' keywords

Top comments (0)