134 lines
2.7 KiB
Go
134 lines
2.7 KiB
Go
package cast
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
|
|
"github.com/pkg/errors"
|
|
"gitlab.com/wpetit/goweb/logger"
|
|
)
|
|
|
|
type Service interface {
|
|
Scan(ctx context.Context) ([]Device, error)
|
|
Find(ctx context.Context, deviceID string) (Device, error)
|
|
NewClient(ctx context.Context, device Device) (Client, error)
|
|
}
|
|
|
|
type Registry struct {
|
|
index map[DeviceType]Service
|
|
}
|
|
|
|
func (r *Registry) NewClient(ctx context.Context, device Device) (Client, error) {
|
|
deviceType := device.DeviceType()
|
|
|
|
srv, exists := r.index[deviceType]
|
|
if !exists {
|
|
return nil, errors.Wrapf(ErrUnknownDeviceType, "device type '%s' is not registered", deviceType)
|
|
}
|
|
|
|
client, err := srv.NewClient(ctx, device)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
return client, nil
|
|
}
|
|
|
|
func (r *Registry) Find(ctx context.Context, deviceID string) (Device, error) {
|
|
for _, srv := range r.index {
|
|
device, err := srv.Find(ctx, deviceID)
|
|
if err != nil {
|
|
logger.Error(ctx, "could not get device", logger.CapturedE(errors.WithStack(err)))
|
|
continue
|
|
}
|
|
|
|
if device != nil {
|
|
return device, nil
|
|
}
|
|
}
|
|
|
|
return nil, errors.WithStack(ErrDeviceNotFound)
|
|
}
|
|
|
|
func (r *Registry) Scan(ctx context.Context) ([]Device, error) {
|
|
results := make([]Device, 0)
|
|
errs := make([]error, 0)
|
|
|
|
var (
|
|
lock sync.Mutex
|
|
wg sync.WaitGroup
|
|
)
|
|
|
|
wg.Add(len(r.index))
|
|
|
|
for _, srv := range r.index {
|
|
func(srv Service) {
|
|
go func() {
|
|
defer wg.Done()
|
|
|
|
devices, err := srv.Scan(ctx)
|
|
if err != nil {
|
|
lock.Lock()
|
|
errs = append(errs, errors.WithStack(err))
|
|
lock.Unlock()
|
|
}
|
|
|
|
lock.Lock()
|
|
results = append(results, devices...)
|
|
lock.Unlock()
|
|
}()
|
|
}(srv)
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
for _, err := range errs {
|
|
logger.Error(ctx, "error occured while scanning", logger.CapturedE(errors.WithStack(err)))
|
|
}
|
|
|
|
return results, nil
|
|
}
|
|
|
|
func (r *Registry) Register(deviceType DeviceType, service Service) {
|
|
r.index[deviceType] = service
|
|
}
|
|
|
|
func NewRegistry() *Registry {
|
|
return &Registry{
|
|
index: make(map[DeviceType]Service),
|
|
}
|
|
}
|
|
|
|
var defaultRegistry = NewRegistry()
|
|
|
|
func NewClient(ctx context.Context, device Device) (Client, error) {
|
|
client, err := defaultRegistry.NewClient(ctx, device)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
return client, nil
|
|
}
|
|
|
|
func Scan(ctx context.Context) ([]Device, error) {
|
|
devices, err := defaultRegistry.Scan(ctx)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
return devices, nil
|
|
}
|
|
|
|
func Find(ctx context.Context, deviceID string) (Device, error) {
|
|
device, err := defaultRegistry.Find(ctx, deviceID)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
return device, nil
|
|
}
|
|
|
|
func Register(deviceType DeviceType, service Service) {
|
|
defaultRegistry.Register(deviceType, service)
|
|
}
|