2020-08-11 04:38:42 +00:00
|
|
|
package events
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
|
|
|
|
2022-02-03 02:02:10 +00:00
|
|
|
"emperror.dev/errors"
|
|
|
|
"github.com/goccy/go-json"
|
|
|
|
"github.com/pterodactyl/wings/system"
|
|
|
|
)
|
2022-01-18 03:23:29 +00:00
|
|
|
|
|
|
|
// Event represents an Event sent over a Bus.
|
2020-08-11 04:38:42 +00:00
|
|
|
type Event struct {
|
|
|
|
Topic string
|
2022-01-18 03:23:29 +00:00
|
|
|
Data interface{}
|
2020-08-11 04:38:42 +00:00
|
|
|
}
|
|
|
|
|
2022-01-18 03:23:29 +00:00
|
|
|
// Bus represents an Event Bus.
|
|
|
|
type Bus struct {
|
2022-02-03 02:02:10 +00:00
|
|
|
*system.SinkPool
|
2020-08-11 04:38:42 +00:00
|
|
|
}
|
|
|
|
|
2022-02-03 02:02:10 +00:00
|
|
|
// NewBus returns a new empty Bus. This is simply a nicer wrapper around the
|
|
|
|
// system.SinkPool implementation that allows for more simplistic usage within
|
|
|
|
// the codebase.
|
|
|
|
//
|
|
|
|
// All of the events emitted out of this bus are byte slices that can be decoded
|
|
|
|
// back into an events.Event interface.
|
2022-01-18 03:23:29 +00:00
|
|
|
func NewBus() *Bus {
|
|
|
|
return &Bus{
|
2022-02-03 02:02:10 +00:00
|
|
|
system.NewSinkPool(),
|
2022-01-18 03:23:29 +00:00
|
|
|
}
|
2020-08-11 04:38:42 +00:00
|
|
|
}
|
|
|
|
|
2022-01-18 03:23:29 +00:00
|
|
|
// Publish publishes a message to the Bus.
|
|
|
|
func (b *Bus) Publish(topic string, data interface{}) {
|
2022-02-03 02:02:10 +00:00
|
|
|
// Some of our actions for the socket support passing a more specific namespace,
|
2022-01-18 03:23:29 +00:00
|
|
|
// such as "backup completed:1234" to indicate which specific backup was completed.
|
|
|
|
//
|
|
|
|
// In these cases, we still need to send the event using the standard listener
|
|
|
|
// name of "backup completed".
|
|
|
|
if strings.Contains(topic, ":") {
|
|
|
|
parts := strings.SplitN(topic, ":", 2)
|
|
|
|
if len(parts) == 2 {
|
|
|
|
topic = parts[0]
|
2020-09-13 03:13:59 +00:00
|
|
|
}
|
2020-09-12 16:26:17 +00:00
|
|
|
}
|
2020-08-11 04:38:42 +00:00
|
|
|
|
2022-02-03 02:02:10 +00:00
|
|
|
enc, err := json.Marshal(Event{Topic: topic, Data: data})
|
|
|
|
if err != nil {
|
|
|
|
panic(errors.WithStack(err))
|
2020-08-11 04:38:42 +00:00
|
|
|
}
|
2022-02-03 02:02:10 +00:00
|
|
|
b.Push(enc)
|
2020-08-11 04:38:42 +00:00
|
|
|
}
|
|
|
|
|
2022-02-03 02:02:10 +00:00
|
|
|
// MustDecode decodes the event byte slice back into an events.Event struct or
|
|
|
|
// panics if an error is encountered during this process.
|
|
|
|
func MustDecode(data []byte) (e Event) {
|
2022-02-05 16:06:11 +00:00
|
|
|
if err := DecodeTo(data, &e); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2022-02-03 02:02:10 +00:00
|
|
|
return
|
2020-08-11 04:38:42 +00:00
|
|
|
}
|
2022-01-20 16:48:18 +00:00
|
|
|
|
2022-02-05 16:06:11 +00:00
|
|
|
// DecodeTo decodes a byte slice of event data into the given interface.
|
|
|
|
func DecodeTo(data []byte, v interface{}) error {
|
2022-02-03 02:02:10 +00:00
|
|
|
if err := json.Unmarshal(data, &v); err != nil {
|
2022-02-05 16:06:11 +00:00
|
|
|
return errors.Wrap(err, "events: failed to decode byte slice")
|
2022-01-20 16:48:18 +00:00
|
|
|
}
|
2022-02-05 16:06:11 +00:00
|
|
|
return nil
|
2022-01-20 16:48:18 +00:00
|
|
|
}
|