func (d *docker) EmitEvents() (<-chan *beacon.Event, error) {
	dockerEvents := make(chan *dockerclient.APIEvents, 1)
	if err := d.client.AddEventListener(dockerEvents); err != nil {
		return nil, errors.Wrap(err, "failed to listen for docker events")
	}
	beaconEvents := make(chan *beacon.Event, 1)
	d.wg.Add(1)
	go func() {
		defer d.wg.Done()
		defer close(beaconEvents)
		running := map[string]struct{}{}
		defer func() {
			if d.stopOnClose {
				for id := range running {
					beaconEvents <- &beacon.Event{
						Action: beacon.Stop,
						Container: &beacon.Container{
							ID: id,
						},
					}
				}
			}
		}()
		sendStart := func(cntr *beacon.Container) bool {
			running[cntr.ID] = struct{}{}
			beaconEvent := &beacon.Event{
				Action:    beacon.Start,
				Container: cntr,
			}
			select {
			case beaconEvents <- beaconEvent:
			case <-d.stop:
				return false
			}
			return true
		}
		sendStop := func(id string) bool {
			if _, ok := running[id]; ok {
				delete(running, id)
			}
			beaconEvent := &beacon.Event{
				Action: beacon.Stop,
				Container: &beacon.Container{
					ID: id,
				},
			}
			select {
			case beaconEvents <- beaconEvent:
			case <-d.stop:
				return false
			}
			return true
		}
		containers, err := d.listContainers()
		if err != nil {
			Logger.Print(err)
		}
		for _, container := range containers {
			if !sendStart(container) {
				return
			}
		}
		for {
			select {
			case dockerEvent, ok := <-dockerEvents:
				if !ok {
					return
				}
				switch dockerEvent.Action {
				case "start":
					if container, err := d.inspectContainer(dockerEvent.Actor.ID); err == nil {
						if !sendStart(container) {
							return
						}
					} else if err != errContainerIgnored {
						Logger.Printf("failed to inspect container %s: %s", dockerEvent.Actor.ID, err)
					}
				case "stop", "die":
					if !sendStop(dockerEvent.Actor.ID) {
						return
					}
				}
			case <-d.stop:
				return
			}
		}
	}()
	Logger.Printf("listening for docker events on %s", d.endpoint)
	return beaconEvents, nil
}
EmitEvents sends Docker events to Beacon.
package docker
import (
	"github.com/BlueDragonX/beacon/beacon"
	dockerclient "github.com/fsouza/go-dockerclient"
	"github.com/pkg/errors"
	"strconv"
	"sync"
)
var (
	errContainerIgnored = errors.New("container ignored")
)
func New(endpoint string, hostIP, serviceLabel string, stopOnClose bool) (beacon.Runtime, error) {
	client, err := dockerclient.NewClient(endpoint)
	if err != nil {
		return nil, errors.Wrap(err, "failed to create docker client")
	}
	if hostIP == "" {
		return nil, errors.Errorf("invalid hostIP %s", hostIP)
	}
	return &docker{
		endpoint:     endpoint,
		client:       client,
		hostIP:       hostIP,
		serviceLabel: serviceLabel,
		stopOnClose:  stopOnClose,
		wg:           &sync.WaitGroup{},
		stop:         make(chan struct{}),
	}, nil
}
type docker struct {
	endpoint     string
	client       *dockerclient.Client
	hostIP       string
	serviceLabel string
	stopOnClose  bool
	wg           *sync.WaitGroup
	stop         chan struct{}
}