Add events (#777)
Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/777 Co-authored-by: konrad <konrad@kola-entertainments.de> Co-committed-by: konrad <konrad@kola-entertainments.de>
This commit is contained in:
97
pkg/events/events.go
Normal file
97
pkg/events/events.go
Normal file
@ -0,0 +1,97 @@
|
||||
// Vikunja is a to-do list application to facilitate your life.
|
||||
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public Licensee as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public Licensee for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public Licensee
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
vmetrics "code.vikunja.io/api/pkg/metrics"
|
||||
"github.com/ThreeDotsLabs/watermill"
|
||||
"github.com/ThreeDotsLabs/watermill/components/metrics"
|
||||
"github.com/ThreeDotsLabs/watermill/message"
|
||||
"github.com/ThreeDotsLabs/watermill/message/router/middleware"
|
||||
"github.com/ThreeDotsLabs/watermill/pubsub/gochannel"
|
||||
)
|
||||
|
||||
var pubsub *gochannel.GoChannel
|
||||
|
||||
// Event represents the event interface used by all events
|
||||
type Event interface {
|
||||
Name() string
|
||||
}
|
||||
|
||||
// InitEvents sets up everything needed to work with events
|
||||
func InitEvents() (err error) {
|
||||
logger := log.NewWatermillLogger()
|
||||
|
||||
router, err := message.NewRouter(
|
||||
message.RouterConfig{},
|
||||
logger,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
router.AddMiddleware(
|
||||
middleware.Retry{
|
||||
MaxRetries: 5,
|
||||
InitialInterval: time.Millisecond * 100,
|
||||
Logger: logger,
|
||||
Multiplier: 2,
|
||||
}.Middleware,
|
||||
middleware.Recoverer,
|
||||
)
|
||||
|
||||
metricsBuilder := metrics.NewPrometheusMetricsBuilder(vmetrics.GetRegistry(), "", "")
|
||||
metricsBuilder.AddPrometheusRouterMetrics(router)
|
||||
|
||||
pubsub = gochannel.NewGoChannel(
|
||||
gochannel.Config{
|
||||
OutputChannelBuffer: 1024,
|
||||
},
|
||||
logger,
|
||||
)
|
||||
|
||||
for topic, funcs := range listeners {
|
||||
for _, handler := range funcs {
|
||||
router.AddNoPublisherHandler(topic+"."+handler.Name(), topic, pubsub, func(msg *message.Message) error {
|
||||
return handler.Handle(msg.Payload)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return router.Run(context.Background())
|
||||
}
|
||||
|
||||
// Dispatch dispatches an event
|
||||
func Dispatch(event Event) error {
|
||||
if isUnderTest {
|
||||
dispatchedTestEvents = append(dispatchedTestEvents, event)
|
||||
return nil
|
||||
}
|
||||
|
||||
content, err := json.Marshal(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := message.NewMessage(watermill.NewUUID(), content)
|
||||
return pubsub.Publish(event.Name(), msg)
|
||||
}
|
36
pkg/events/listeners.go
Normal file
36
pkg/events/listeners.go
Normal file
@ -0,0 +1,36 @@
|
||||
// Vikunja is a to-do list application to facilitate your life.
|
||||
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public Licensee as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public Licensee for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public Licensee
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package events
|
||||
|
||||
import "github.com/ThreeDotsLabs/watermill/message"
|
||||
|
||||
// Listener represents something that listens to events
|
||||
type Listener interface {
|
||||
Handle(payload message.Payload) error
|
||||
Name() string
|
||||
}
|
||||
|
||||
var listeners map[string][]Listener
|
||||
|
||||
func init() {
|
||||
listeners = make(map[string][]Listener)
|
||||
}
|
||||
|
||||
// RegisterListener is used to register a listener when a specific event happens
|
||||
func RegisterListener(name string, listener Listener) {
|
||||
listeners[name] = append(listeners[name], listener)
|
||||
}
|
49
pkg/events/testing.go
Normal file
49
pkg/events/testing.go
Normal file
@ -0,0 +1,49 @@
|
||||
// Vikunja is a to-do list application to facilitate your life.
|
||||
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public Licensee as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public Licensee for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public Licensee
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package events
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
isUnderTest bool
|
||||
dispatchedTestEvents []Event
|
||||
)
|
||||
|
||||
// Fake sets up the "test mode" of the events package. Typically you'd call this function in the TestMain function
|
||||
// in the package you're testing. It will prevent any events from being fired, instead they will be recorded and be
|
||||
// available for assertions.
|
||||
func Fake() {
|
||||
isUnderTest = true
|
||||
dispatchedTestEvents = nil
|
||||
}
|
||||
|
||||
// AssertDispatched asserts an event has been dispatched.
|
||||
func AssertDispatched(t *testing.T, event Event) {
|
||||
var found bool
|
||||
for _, testEvent := range dispatchedTestEvents {
|
||||
if event.Name() == testEvent.Name() {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
assert.True(t, found, "Failed to assert "+event.Name()+" has been dispatched.")
|
||||
}
|
Reference in New Issue
Block a user