canape/backend/events/notifier.go
Lucas BEE 2bd90e5cb5 events: Add an error channel
The server now sends errors to the client
2019-05-27 12:18:05 +00:00

142 lines
2.8 KiB
Go

package events
import (
"sync"
)
// ErrorLevel is the level of the ServerError
type ErrorLevel string
// Status is the status of an event
type Status string
// Different ErrorLevels and statuses
const (
// ErrorLevel
WarningError ErrorLevel = "warning"
FatalError ErrorLevel = "fatal"
// Statuses
OK Status = "ok"
Error Status = "error"
)
// Event is the base of a message
type Event struct {
Type string `json:"type"`
Status Status `json:"status"`
}
// ClientMessage represents a message sent by the client
type ClientMessage struct {
Event
Message string `json:"message"`
}
// ServerEvent represents an event sent to the client
type ServerEvent struct {
Event
Data interface{} `json:"message"`
}
// ErrorEvent represents an event error
type ErrorEvent struct {
Level ErrorLevel `json:"level"`
Message string `json:"message"`
}
// ServerError represents an error sent to the client
type ServerError struct {
Event
ErrorEvent `json:"error"`
}
// Eventer define an interface that any eventer must follow
type Eventer interface {
Subscribe(func())
Unsubscribe()
Launch()
Name() string
}
// Notifier represents the base of any Eventer
// Notify implements Subscribe and Unsubscribe methods
type Notifier struct {
sync.RWMutex
subscribed bool
done chan struct{}
eventStream chan ServerEvent
errorStream chan ServerError
}
// NewNotifier returns a new notifier
func NewNotifier(eventStream chan ServerEvent, errorStream chan ServerError) *Notifier {
return &Notifier{
eventStream: eventStream,
errorStream: errorStream,
done: make(chan struct{}),
}
}
// Subscribe subscribes a client on the Notifier
func (t *Notifier) Subscribe(launch func()) {
t.Lock()
defer t.Unlock()
// Check if already subscribed
if t.subscribed {
return
}
t.subscribed = true
go launch()
}
// Unsubscribe unsubscribes a client from receiving any more events from
// the Notifier
func (t *Notifier) Unsubscribe() {
t.Lock()
defer t.Unlock()
// Check if already unsubscribed
if !t.subscribed {
return
}
t.subscribed = false
t.done <- struct{}{}
}
// Error sends an error into the errorStream channel
func (t *Notifier) Error(name string, err error) {
t.errorStream <- ServerError{
Event: Event{
Type: name,
Status: Error,
},
ErrorEvent: ErrorEvent{
Level: WarningError,
Message: err.Error(),
},
}
}
// FatalError sends an error into the errorStream channel and tell the client
// that the error is fatal, the notifier won't communicate until a new
// subscribe
func (t *Notifier) FatalError(name string, err error) {
t.Lock()
defer t.Unlock()
t.errorStream <- ServerError{
Event: Event{
Type: name,
Status: Error,
},
ErrorEvent: ErrorEvent{
Level: FatalError,
Message: err.Error(),
},
}
t.subscribed = false
}