func (c *channelDiscovery) handleDiscoveryResponse(peerEndpoints []string) appdata.ResponseHandler {
	return func(response []byte) (extcommon.Values, error) {
		servicesMap := make(servicesByPeer)
		err := json.Unmarshal(response, &servicesMap)
		if err != nil {
			return nil, err
		}
		services := make(extcommon.Values, len(peerEndpoints))
		for i, k := range peerEndpoints {
			servicesForPeer, ok := servicesMap[k]
			if !ok || servicesForPeer == nil {
				services[i] = nil
			} else {
				services[i] = servicesForPeer
			}
		}
		return services, nil
	}
}
handleDiscoveryResponse is a client-side handler of a response from a remote peer. It ensures that
the response from the peer is added to Values in the same order as the given peer endpoints.
package discovery
import (
	"context"
	"encoding/json"
	"time"
	"github.com/bluele/gcache"
	gproto "github.com/hyperledger/fabric-protos-go/gossip"
	"github.com/hyperledger/fabric/common/flogging"
	gossipapi "github.com/hyperledger/fabric/extensions/gossip/api"
	"github.com/hyperledger/fabric/gossip/api"
	"github.com/hyperledger/fabric/gossip/comm"
	gcommon "github.com/hyperledger/fabric/gossip/common"
	"github.com/hyperledger/fabric/gossip/discovery"
	extcommon "github.com/trustbloc/fabric-peer-ext/pkg/common"
	extdiscovery "github.com/trustbloc/fabric-peer-ext/pkg/common/discovery"
	"github.com/trustbloc/fabric-peer-ext/pkg/gossip/appdata"
)
var logger = flogging.MustGetLogger("sidetree_peer")
const (
	handlerDataType = "ENDPOINT_DISCOVERY"
	defaultCacheExpirationTime = 5 * time.Minute
	defaultGossipTimeout       = 5 * time.Second
	defaultGossipMaxAttempts   = 5
	defaultGossipMaxPeers      = 3
)
type appDataHandlerRegistry interface {
	Register(dataType string, handler appdata.Handler) error
}
type gossipService interface {
	PeersOfChannel(id gcommon.ChannelID) []discovery.NetworkMember
	SelfMembershipInfo() discovery.NetworkMember
	IdentityInfo() api.PeerIdentitySet
	Send(msg *gproto.GossipMessage, peers ...*comm.RemotePeer)
}
type gossipProvider interface {
	GetGossipService() gossipapi.GossipService
}
type peerConfig interface {
	PeerAddress() string
}
type discoveryConfig interface {
	DiscoveryCacheExpirationTime() time.Duration
	DiscoveryGossipMaxAttempts() int
	DiscoveryGossipTimeout() time.Duration
	DiscoveryGossipMaxPeers() int
}
type retriever interface {
	Retrieve(ctxt context.Context, request *appdata.Request, responseHandler appdata.ResponseHandler, allSet appdata.AllSet, opts ...appdata.Option) (extcommon.Values, error)
}
type servicesByPeer = map[string][]Service
type config struct {
	gossipTimeout       time.Duration
	gossipMaxAttempts   int
	gossipMaxPeers      int
	cacheExpirationTime time.Duration
}
type Discovery struct {
	config
	peerConfig
	discoveryCache gcache.Cache
	marshal        func(interface{}) ([]byte, error)
	unmarshal      func([]byte, interface{}) error
}
func New(handlerRegistry appDataHandlerRegistry, gossipProvider gossipProvider, peerCfg peerConfig, discoveryCfg discoveryConfig) *Discovery {
	cfg := newConfig(discoveryCfg)
	logger.Infof("Creating discovery service with config: %+v", cfg)
	d := &Discovery{
		config:     cfg,
		peerConfig: peerCfg,
		marshal:    json.Marshal,
		unmarshal:  json.Unmarshal,
		discoveryCache: gcache.New(0).LoaderFunc(func(chID interface{}) (interface{}, error) {
			return newChannelDiscovery(chID.(string), cfg, peerCfg, gossipProvider.GetGossipService()), nil
		}).Build(),
	}
	if err := handlerRegistry.Register(handlerDataType, d.handleDiscoveryRequest); err != nil {
		panic(err)
	}
	return d
}
func (d *Discovery) ServicesForChannel(channelID string) []Service {
	return d.forChannel(channelID).services()
}
func (d *Discovery) UpdateLocalServicesForChannel(channelID string, services []Service) {
	d.forChannel(channelID).updateLocalServices(services)
}
func (d *Discovery) forChannel(channelID string) *channelDiscovery {
	c, err := d.discoveryCache.Get(channelID)
	if err != nil {
		panic(err)
	}
	return c.(*channelDiscovery)
}
func (d *Discovery) handleDiscoveryRequest(channelID string, req *gproto.AppDataRequest, responder appdata.Responder) {
	logger.Debugf("[%s] Handling discovery request", channelID)
	var peerEndpoints []string
	err := d.unmarshal(req.Request, &peerEndpoints)
	if err != nil {
		logger.Errorf("Error unmarshalling peer endpoints in request: %s")
		responder.Respond(nil)
		return
	}
	logger.Debugf("[%s] Got discovery request for endpoints: %s", channelID, peerEndpoints)
	response := make(servicesByPeer)
	for _, peerEndpoint := range peerEndpoints {
		response[peerEndpoint] = d.forChannel(channelID).servicesForPeer(peerEndpoint)
	}
	respBytes, err := d.marshal(response)
	if err != nil {
		logger.Errorf("Error marshalling response: %s")
	}
	responder.Respond(respBytes)
}