Files
weave-scope/probe/controls/controls.go
Krzesimir Nowak 41193b428e Make control handlers registry an object and extend its functionality
It is not a singleton anymore. Instead it is an object with a registry
backend. The default registry backend is provided, which is equivalent
to what used to be before. Custom backend can be provided for testing
purposes.

The registry also supports batch operations to remove and add handlers
as an atomic step.
2016-08-12 17:03:42 +02:00

132 lines
3.6 KiB
Go

package controls
import (
"sync"
"github.com/weaveworks/scope/common/xfer"
)
// HandlerRegistryBackend is an interface for storing control request
// handlers.
type HandlerRegistryBackend interface {
// Lock locks the backend, so the batch insertions or
// removals can be performed.
Lock()
// Unlock unlocks the registry.
Unlock()
// Register a new control handler under a given
// id. Implementations should not call Lock() or Unlock()
// here, it will be done by HandlerRegistry.
Register(control string, f xfer.ControlHandlerFunc)
// Rm deletes the handler for a given name. Implementations
// should not call Lock() or Unlock() here, it will be done by
// HandlerRegistry.
Rm(control string)
// Handler gets the handler for a control. Implementations
// should not call Lock() or Unlock() here, it will be done by
// HandlerRegistry.
Handler(control string) (xfer.ControlHandlerFunc, bool)
}
type defaultBackend struct {
handlers map[string]xfer.ControlHandlerFunc
mtx sync.Mutex
}
// NewDefaultHandlerRegistryBackend creates a default backend for
// handler registry.
func NewDefaultHandlerRegistryBackend() HandlerRegistryBackend {
return &defaultBackend{
handlers: map[string]xfer.ControlHandlerFunc{},
}
}
// Lock locks the registry, so the batch insertions or
// removals can be performed.
func (b *defaultBackend) Lock() {
b.mtx.Lock()
}
// Unlock unlocks the registry.
func (b *defaultBackend) Unlock() {
b.mtx.Unlock()
}
// Register a new control handler under a given id.
func (b *defaultBackend) Register(control string, f xfer.ControlHandlerFunc) {
b.handlers[control] = f
}
// Rm deletes the handler for a given name.
func (b *defaultBackend) Rm(control string) {
delete(b.handlers, control)
}
// Handler gets the handler for a control.
func (b *defaultBackend) Handler(control string) (xfer.ControlHandlerFunc, bool) {
handler, ok := b.handlers[control]
return handler, ok
}
// HandlerRegistry uses backend for storing and retrieving control
// requests handlers.
type HandlerRegistry struct {
backend HandlerRegistryBackend
}
// NewDefaultHandlerRegistry creates a registry with a default
// backend.
func NewDefaultHandlerRegistry() *HandlerRegistry {
return NewHandlerRegistry(NewDefaultHandlerRegistryBackend())
}
// NewHandlerRegistry creates a registry with a custom backend.
func NewHandlerRegistry(backend HandlerRegistryBackend) *HandlerRegistry {
return &HandlerRegistry{
backend: backend,
}
}
// Register registers a new control handler under a given name.
func (r *HandlerRegistry) Register(control string, f xfer.ControlHandlerFunc) {
r.backend.Lock()
defer r.backend.Unlock()
r.backend.Register(control, f)
}
// Rm deletes the handler for a given name.
func (r *HandlerRegistry) Rm(control string) {
r.backend.Lock()
defer r.backend.Unlock()
r.backend.Rm(control)
}
// Batch first deletes handlers for given names in toRemove then
// registers new handlers for given names in toAdd.
func (r *HandlerRegistry) Batch(toRemove []string, toAdd map[string]xfer.ControlHandlerFunc) {
r.backend.Lock()
defer r.backend.Unlock()
for _, control := range toRemove {
r.backend.Rm(control)
}
for control, handler := range toAdd {
r.backend.Register(control, handler)
}
}
// HandleControlRequest performs a control request.
func (r *HandlerRegistry) HandleControlRequest(req xfer.Request) xfer.Response {
h, ok := r.handler(req.Control)
if !ok {
return xfer.ResponseErrorf("Control %q not recognised", req.Control)
}
return h(req)
}
func (r *HandlerRegistry) handler(control string) (xfer.ControlHandlerFunc, bool) {
r.backend.Lock()
defer r.backend.Unlock()
return r.backend.Handler(control)
}