func (b *beacon) Close() error {
	b.runtime.Close()
	return nil
}
Close the beacon.
package beacon
import (
	"github.com/pkg/errors"
	"sync"
)
func New(runtime Runtime, routes []Route) (Beacon, error) {
	if runtime == nil {
		return nil, errors.New("runtime cannot be nil")
	}
	if len(routes) == 0 {
		return nil, errors.New("routes cannot be empty")
	}
	routesCp := make([]Route, len(routes))
	copy(routesCp, routes)
	return &beacon{
		runtime:    runtime,
		routes:     routesCp,
		containers: map[string]*Container{},
		lock:       &sync.Mutex{},
	}, nil
}
type Beacon interface {
	Run() error
	Close() error
	Containers(filter Filter) []*Container
}
type beacon struct {
	runtime    Runtime
	routes     []Route
	containers map[string]*Container
	lock       *sync.Mutex
}
func (b *beacon) Run() error {
	defer func() {
		for _, route := range b.routes {
			route.Close()
		}
	}()
	events, err := b.runtime.EmitEvents()
	if err != nil {
		return errors.Wrap(err, "failed to start runtime")
	}
	for {
		event, ok := <-events
		if !ok {
			break
		}
		if err := b.handle(event); err != nil {
			Logger.Printf("unable to process event: %s\n", err)
		}
	}
	return nil
}
func (b *beacon) handle(event *Event) error {
	b.lock.Lock()
	defer b.lock.Unlock()
	var backendEvent *Event
	switch event.Action {
	case Start, Update:
		oldContainer, exists := b.containers[event.Container.ID]
		if !exists {
			newContainer := event.Container.Copy()
			b.containers[event.Container.ID] = newContainer
			backendEvent = &Event{
				Action:    Start,
				Container: newContainer,
			}
		} else if !event.Container.Equal(oldContainer) {
			newContainer := event.Container.Copy()
			b.containers[event.Container.ID] = newContainer
			backendEvent = &Event{
				Action:    Update,
				Container: newContainer,
			}
		} else {
			return nil
		}
	case Stop:
		if oldContainer, exists := b.containers[event.Container.ID]; exists {
			delete(b.containers, event.Container.ID)
			backendEvent = &Event{
				Action:    event.Action,
				Container: oldContainer,
			}
		} else {
			return nil
		}
	default:
		return errors.Errorf("invalid action %s on container %s", event.Action, event.Container.ID)
	}
	for _, route := range b.routes {
		if route.MatchContainer(backendEvent.Container) {
			if err := route.ProcessEvent(backendEvent.Copy()); err != nil {
				Logger.Printf("discarding event %s for container %s: %s", event.Action, event.Container.ID, err)
			}
		}
	}
	return nil
}
func (b *beacon) Containers(filter Filter) []*Container {
	if filter == nil {
		filter = &allFilter{}
	}
	b.lock.Lock()
	defer b.lock.Unlock()
	containers := []*Container{}
	for _, container := range b.containers {
		if filter == nil || filter.MatchContainer(container) {
			containers = append(containers, container.Copy())
		}
	}
	return containers
}