func NewGroupStore(addr string, concurrency int, ftlsConfig *ftls.Config, opts ...grpc.DialOption) (store.GroupStore, error) {
	stor := &groupStore{
		addr:             addr,
		ftlsc:            ftlsConfig,
		opts:             opts,
		handlersDoneChan: make(chan struct{}),
	}

	stor.pendingLookupReqChan = make(chan *asyncGroupLookupRequest, concurrency)
	stor.freeLookupReqChan = make(chan *asyncGroupLookupRequest, concurrency)
	stor.freeLookupResChan = make(chan *asyncGroupLookupResponse, concurrency)
	for i := 0; i < cap(stor.freeLookupReqChan); i++ {
		stor.freeLookupReqChan <- &asyncGroupLookupRequest{resChan: make(chan *asyncGroupLookupResponse, 1)}
	}
	for i := 0; i < cap(stor.freeLookupResChan); i++ {
		stor.freeLookupResChan <- &asyncGroupLookupResponse{}
	}
	go stor.handleLookupStream()

	stor.pendingReadReqChan = make(chan *asyncGroupReadRequest, concurrency)
	stor.freeReadReqChan = make(chan *asyncGroupReadRequest, concurrency)
	stor.freeReadResChan = make(chan *asyncGroupReadResponse, concurrency)
	for i := 0; i < cap(stor.freeReadReqChan); i++ {
		stor.freeReadReqChan <- &asyncGroupReadRequest{resChan: make(chan *asyncGroupReadResponse, 1)}
	}
	for i := 0; i < cap(stor.freeReadResChan); i++ {
		stor.freeReadResChan <- &asyncGroupReadResponse{}
	}
	go stor.handleReadStream()

	stor.pendingWriteReqChan = make(chan *asyncGroupWriteRequest, concurrency)
	stor.freeWriteReqChan = make(chan *asyncGroupWriteRequest, concurrency)
	stor.freeWriteResChan = make(chan *asyncGroupWriteResponse, concurrency)
	for i := 0; i < cap(stor.freeWriteReqChan); i++ {
		stor.freeWriteReqChan <- &asyncGroupWriteRequest{resChan: make(chan *asyncGroupWriteResponse, 1)}
	}
	for i := 0; i < cap(stor.freeWriteResChan); i++ {
		stor.freeWriteResChan <- &asyncGroupWriteResponse{}
	}
	go stor.handleWriteStream()

	stor.pendingDeleteReqChan = make(chan *asyncGroupDeleteRequest, concurrency)
	stor.freeDeleteReqChan = make(chan *asyncGroupDeleteRequest, concurrency)
	stor.freeDeleteResChan = make(chan *asyncGroupDeleteResponse, concurrency)
	for i := 0; i < cap(stor.freeDeleteReqChan); i++ {
		stor.freeDeleteReqChan <- &asyncGroupDeleteRequest{resChan: make(chan *asyncGroupDeleteResponse, 1)}
	}
	for i := 0; i < cap(stor.freeDeleteResChan); i++ {
		stor.freeDeleteResChan <- &asyncGroupDeleteResponse{}
	}
	go stor.handleDeleteStream()

	stor.pendingLookupGroupReqChan = make(chan *asyncGroupLookupGroupRequest, concurrency)
	stor.freeLookupGroupReqChan = make(chan *asyncGroupLookupGroupRequest, concurrency)
	stor.freeLookupGroupResChan = make(chan *asyncGroupLookupGroupResponse, concurrency)
	for i := 0; i < cap(stor.freeLookupGroupReqChan); i++ {
		stor.freeLookupGroupReqChan <- &asyncGroupLookupGroupRequest{resChan: make(chan *asyncGroupLookupGroupResponse, 1)}
	}
	for i := 0; i < cap(stor.freeLookupGroupResChan); i++ {
		stor.freeLookupGroupResChan <- &asyncGroupLookupGroupResponse{}
	}
	go stor.handleLookupGroupStream()

	stor.pendingReadGroupReqChan = make(chan *asyncGroupReadGroupRequest, concurrency)
	stor.freeReadGroupReqChan = make(chan *asyncGroupReadGroupRequest, concurrency)
	stor.freeReadGroupResChan = make(chan *asyncGroupReadGroupResponse, concurrency)
	for i := 0; i < cap(stor.freeReadGroupReqChan); i++ {
		stor.freeReadGroupReqChan <- &asyncGroupReadGroupRequest{resChan: make(chan *asyncGroupReadGroupResponse, 1)}
	}
	for i := 0; i < cap(stor.freeReadGroupResChan); i++ {
		stor.freeReadGroupResChan <- &asyncGroupReadGroupResponse{}
	}
	go stor.handleReadGroupStream()

	return stor, nil
}
func NewGroupStore(addr string, concurrency int, ftlsConfig *ftls.Config, opts ...grpc.DialOption) (store.GroupStore, error) {
	stor := &groupStore{
		addr:             addr,
		ftlsc:            ftlsConfig,
		opts:             opts,
		handlersDoneChan: make(chan struct{}),
	}

	stor.pendingLookupReqChan = make(chan *asyncGroupLookupRequest, concurrency)
	stor.freeLookupReqChan = make(chan *asyncGroupLookupRequest, concurrency)
	stor.freeLookupResChan = make(chan *asyncGroupLookupResponse, concurrency)
	for i := 0; i < cap(stor.freeLookupReqChan); i++ {
		stor.freeLookupReqChan <- &asyncGroupLookupRequest{resChan: make(chan *asyncGroupLookupResponse, 1)}
	}
	for i := 0; i < cap(stor.freeLookupResChan); i++ {
		stor.freeLookupResChan <- &asyncGroupLookupResponse{}
	}
	go stor.handleLookupStream()

	stor.pendingReadReqChan = make(chan *asyncGroupReadRequest, concurrency)
	stor.freeReadReqChan = make(chan *asyncGroupReadRequest, concurrency)
	stor.freeReadResChan = make(chan *asyncGroupReadResponse, concurrency)
	for i := 0; i < cap(stor.freeReadReqChan); i++ {
		stor.freeReadReqChan <- &asyncGroupReadRequest{resChan: make(chan *asyncGroupReadResponse, 1)}
	}
	for i := 0; i < cap(stor.freeReadResChan); i++ {
		stor.freeReadResChan <- &asyncGroupReadResponse{}
	}
	go stor.handleReadStream()

	stor.pendingWriteReqChan = make(chan *asyncGroupWriteRequest, concurrency)
	stor.freeWriteReqChan = make(chan *asyncGroupWriteRequest, concurrency)
	stor.freeWriteResChan = make(chan *asyncGroupWriteResponse, concurrency)
	for i := 0; i < cap(stor.freeWriteReqChan); i++ {
		stor.freeWriteReqChan <- &asyncGroupWriteRequest{resChan: make(chan *asyncGroupWriteResponse, 1)}
	}
	for i := 0; i < cap(stor.freeWriteResChan); i++ {
		stor.freeWriteResChan <- &asyncGroupWriteResponse{}
	}
	go stor.handleWriteStream()

	stor.pendingDeleteReqChan = make(chan *asyncGroupDeleteRequest, concurrency)
	stor.freeDeleteReqChan = make(chan *asyncGroupDeleteRequest, concurrency)
	stor.freeDeleteResChan = make(chan *asyncGroupDeleteResponse, concurrency)
	for i := 0; i < cap(stor.freeDeleteReqChan); i++ {
		stor.freeDeleteReqChan <- &asyncGroupDeleteRequest{resChan: make(chan *asyncGroupDeleteResponse, 1)}
	}
	for i := 0; i < cap(stor.freeDeleteResChan); i++ {
		stor.freeDeleteResChan <- &asyncGroupDeleteResponse{}
	}
	go stor.handleDeleteStream()

	stor.pendingLookupGroupReqChan = make(chan *asyncGroupLookupGroupRequest, concurrency)
	stor.freeLookupGroupReqChan = make(chan *asyncGroupLookupGroupRequest, concurrency)
	stor.freeLookupGroupResChan = make(chan *asyncGroupLookupGroupResponse, concurrency)
	for i := 0; i < cap(stor.freeLookupGroupReqChan); i++ {
		stor.freeLookupGroupReqChan <- &asyncGroupLookupGroupRequest{resChan: make(chan *asyncGroupLookupGroupResponse, 1)}
	}
	for i := 0; i < cap(stor.freeLookupGroupResChan); i++ {
		stor.freeLookupGroupResChan <- &asyncGroupLookupGroupResponse{}
	}
	go stor.handleLookupGroupStream()

	stor.pendingReadGroupReqChan = make(chan *asyncGroupReadGroupRequest, concurrency)
	stor.freeReadGroupReqChan = make(chan *asyncGroupReadGroupRequest, concurrency)
	stor.freeReadGroupResChan = make(chan *asyncGroupReadGroupResponse, concurrency)
	for i := 0; i < cap(stor.freeReadGroupReqChan); i++ {
		stor.freeReadGroupReqChan <- &asyncGroupReadGroupRequest{resChan: make(chan *asyncGroupReadGroupResponse, 1)}
	}
	for i := 0; i < cap(stor.freeReadGroupResChan); i++ {
		stor.freeReadGroupResChan <- &asyncGroupReadGroupResponse{}
	}
	go stor.handleReadGroupStream()

	return stor, nil
}
// NewGroupStore creates a GroupStore connection via grpc to the given
// address.