From 99b77ca65a3c10df17cc6be6406269c09ae411c5 Mon Sep 17 00:00:00 2001 From: Tim Liu Date: Fri, 25 Sep 2020 11:59:44 +0000 Subject: [PATCH] Add source and update README --- README.md | 106 +++++++++++++++++++++++++++++++++++++++++++++++++- dispatcher.go | 49 +++++++++++++++++++++++ event.go | 9 +++++ job.go | 8 ++++ listener.go | 6 +++ 5 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 dispatcher.go create mode 100644 event.go create mode 100644 job.go create mode 100644 listener.go diff --git a/README.md b/README.md index fcda02b..c690316 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,106 @@ # event -Event listener and dispatcher for Golang +A go package for event listener and dispatcher with channel. + +**Original Place: [event-listener-and-dispatcher-example-with-golang](http://www.inanzzz.com/index.php/post/2qdl/event-listener-and-dispatcher-example-with-golang)** + +## Features + +- One dispatcher can register many listeners. + +- One dispatcher can register many events for a specific given listener. + +- One dispatcher can dispatch many events. + +- One listener can listen on many events. + +- One event can be linked to one event type. + +- The dispatcher prevents registering duplicated events. + +- The dispatcher prevents dispatching non-registered events. + +## Usage Sample + +### Create your own events + +user/created.go: + +```go +package user + +import ( + "log" + "time" + + "github.com/tim-ywliu/event" +) + +const Created event.Name = "user.created" + +type CreatedEvent struct { + Time time.Time + ID string +} + +func (e CreatedEvent) Handle() { + log.Printf("creating: %+v\n", e) +} +``` + +### Write your event listener + +user/listener.go: + +```go +package user + +import ( + "log" +) + +type UserListener struct{} + +func (u UserListener) Listen(event interface{}) { + switch event := event.(type) { + case CreatedEvent: + event.Handle() + default: + log.Printf("registered an invalid user event: %T\n", event) + } +} +``` + +### Write your event dispatch method + +user/dispatcher.go: + +```go +package user + +var userDispatcher *event.Dispatcher + +import ( + "log" + "time" + + "github.com/tim-ywliu/event" +) + +func RegisterUserDispatcher() error { + userDispatcher = event.NewDispatcher() + if err := userDispatcher.Register(UserListener{}, Created); err != nil { + return err + } + return nil +} + +func DispatchUserCreatedEvent() { + err := userDispatcher.Dispatch(Created, CreatedEvent{ + Time: time.Now().UTC(), + ID: "111", + }) + if err != nil { + log.Println(err) + } +} +``` diff --git a/dispatcher.go b/dispatcher.go new file mode 100644 index 0000000..7010077 --- /dev/null +++ b/dispatcher.go @@ -0,0 +1,49 @@ +package event + +import ( + "fmt" +) + +type Dispatcher struct { + jobs chan job + events map[Name]Listener +} + +func NewDispatcher() *Dispatcher { + d := &Dispatcher{ + jobs: make(chan job), + events: make(map[Name]Listener), + } + + go d.consume() + + return d +} + +func (d *Dispatcher) Register(listener Listener, names ...Name) error { + for _, name := range names { + if _, ok := d.events[name]; ok { + return fmt.Errorf("the '%s' event is already registered", name) + } + + d.events[name] = listener + } + + return nil +} + +func (d *Dispatcher) Dispatch(name Name, event interface{}) error { + if _, ok := d.events[name]; !ok { + return fmt.Errorf("the '%s' event is not registered", name) + } + + d.jobs <- job{eventName: name, eventType: event} + + return nil +} + +func (d *Dispatcher) consume() { + for job := range d.jobs { + d.events[job.eventName].Listen(job.eventType) + } +} diff --git a/event.go b/event.go new file mode 100644 index 0000000..8fd1f45 --- /dev/null +++ b/event.go @@ -0,0 +1,9 @@ +package event + +// All custom events names must be of this type. +type Name string + +// All custom event types must satisfy this interface. +type Event interface { + Handle() +} diff --git a/job.go b/job.go new file mode 100644 index 0000000..101a2d2 --- /dev/null +++ b/job.go @@ -0,0 +1,8 @@ +package event + +// job represents events. When a new event is dispatched, it +// gets tuned into a job and put into `Dispatcher.jobs` channel. +type job struct { + eventName Name + eventType interface{} +} diff --git a/listener.go b/listener.go new file mode 100644 index 0000000..9e459a1 --- /dev/null +++ b/listener.go @@ -0,0 +1,6 @@ +package event + +// All custom event listeners must satisfy this interface. +type Listener interface { + Listen(event interface{}) +}