func (d *DockerDiscovery) listenerForContainer(cntnr *docker.Container) *ChangeListener {
	svcPortStr, ok := cntnr.Config.Labels["SidecarListener"]
	if !ok {
		return nil
	}
	id := cntnr.ID
	if len(id) > 12 {
		id = id[:12]
	}
	svc := d.findServiceByID(id)
	if svc == nil {
		return nil
	}
	listenPort := portForServicePort(svc, svcPortStr, "tcp")  
	if listenPort == nil {
		log.Warnf(
			"SidecarListener label found on %s, but no matching ServicePort! '%s'",
			svc.ID, svcPortStr,
		)
		return nil
	}
	return &ChangeListener{
		Name: svc.ListenerName(),
		Url:  fmt.Sprintf("http://%s:%d/sidecar/update", listenPort.IP, listenPort.Port),
	}
}
listenerForContainer returns a ChangeListener for a container if one
is configured.
package discovery
import (
	"fmt"
	"strconv"
	"sync"
	"time"
	director "github.com/relistan/go-director"
	log "github.com/sirupsen/logrus"
	"github.com/NinesStack/sidecar/service"
	"github.com/fsouza/go-dockerclient"
)
const (
	CacheDrainInterval = 10 * time.Minute  
)
type DockerClient interface {
	InspectContainer(id string) (*docker.Container, error)
	ListContainers(opts docker.ListContainersOptions) ([]docker.APIContainers, error)
	AddEventListener(listener chan<- *docker.APIEvents) error
	RemoveEventListener(listener chan *docker.APIEvents) error
	Ping() error
}
type DockerDiscovery struct {
	events         chan *docker.APIEvents        
	endpoint       string                        
	services       []*service.Service            
	ClientProvider func() (DockerClient, error)  
	serviceNamer   ServiceNamer                  
	advertiseIp    string                        
	containerCache *ContainerCache               
	sleepInterval  time.Duration                 
	sync.RWMutex                                 
}
func NewDockerDiscovery(endpoint string, svcNamer ServiceNamer, ip string) *DockerDiscovery {
	discovery := DockerDiscovery{
		endpoint:       endpoint,
		events:         make(chan *docker.APIEvents),
		containerCache: NewContainerCache(),
		serviceNamer:   svcNamer,
		advertiseIp:    ip,
		sleepInterval:  DefaultSleepInterval,
	}
	discovery.ClientProvider = discovery.getDockerClient
	return &discovery
}
func (d *DockerDiscovery) getDockerClient() (DockerClient, error) {
	if d.endpoint != "" {
		client, err := docker.NewClient(d.endpoint)
		if err != nil {
			return nil, err
		}
		return client, nil
	}
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return nil, err
	}
	return client, nil
}
func (d *DockerDiscovery) HealthCheck(svc *service.Service) (string, string) {
	container, err := d.inspectContainer(svc)
	if err != nil {
		return "", ""
	}
	return container.Config.Labels["HealthCheck"], container.Config.Labels["HealthCheckArgs"]
}
func (d *DockerDiscovery) inspectContainer(svc *service.Service) (*docker.Container, error) {
	container := d.containerCache.Get(svc.ID)
	if container != nil {
		return container, nil
	}
	client, err := d.ClientProvider()
	if err != nil {
		log.Errorf("Error when creating Docker client: %s\n", err.Error())
		return nil, err
	}
	container, err = client.InspectContainer(svc.ID)
	if err != nil {
		log.Errorf("Error inspecting container : %v\n", svc.ID)
		return nil, err
	}
	d.containerCache.Set(svc, container)
	return container, nil
}
func (d *DockerDiscovery) Run(looper director.Looper) {
	connQuitChan := make(chan bool)
	go d.manageConnection(connQuitChan)
	go func() {
		looper.Loop(func() error {
			select {
			case event := <-d.events:
				if event == nil {
					return nil
				}
				log.Debugf("Event: %#v\n", event)
				d.handleEvent(*event)
			case <-time.After(d.sleepInterval):
				d.getContainers()
			case <-time.After(CacheDrainInterval):
				d.containerCache.Drain(len(d.services))
			}
			return nil
		})
		close(connQuitChan)
	}()
}
func (d *DockerDiscovery) Services() []service.Service {
	d.RLock()
	defer d.RUnlock()
	svcList := make([]service.Service, len(d.services))
	for i, svc := range d.services {
		svcList[i] = *svc
	}
	return svcList
}
func (d *DockerDiscovery) Listeners() []ChangeListener {
	var listeners []ChangeListener
	for _, cntnr := range d.services {
		container, err := d.inspectContainer(cntnr)
		if err != nil {
			continue
		}
		listener := d.listenerForContainer(container)
		if listener != nil {
			listeners = append(listeners, *listener)
		}
	}
	return listeners
}
func (d *DockerDiscovery) findServiceByID(id string) *service.Service {
	for _, svc := range d.services {
		if svc.ID == id {
			return svc
		}
	}
	return nil
}