1
0

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:
konrad
2021-02-02 22:48:37 +00:00
parent a71aa0c898
commit 0ab9ce9ec4
70 changed files with 1636 additions and 283 deletions

97
pkg/events/events.go Normal file
View 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
View 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
View 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.")
}