126 lines
3.3 KiB
Go
126 lines
3.3 KiB
Go
/*
|
|
Copyright IBM Corp. 2016-2017 All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
package common
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"fmt"
|
|
"strings"
|
|
|
|
cb "github.com/hyperledger/fabric-protos-go/common"
|
|
ab "github.com/hyperledger/fabric-protos-go/orderer"
|
|
"github.com/pkg/errors"
|
|
"google.golang.org/grpc"
|
|
)
|
|
|
|
// OrdererClient represents a client for communicating with an ordering
|
|
// service
|
|
type OrdererClient struct {
|
|
*CommonClient
|
|
}
|
|
|
|
// NewOrdererClientFromEnv creates an instance of an OrdererClient from the
|
|
// global Viper instance
|
|
func NewOrdererClientFromEnv() (*OrdererClient, error) {
|
|
address, clientConfig, err := configFromEnv("orderer")
|
|
if err != nil {
|
|
return nil, errors.WithMessage(err, "failed to load config for OrdererClient")
|
|
}
|
|
cc, err := newCommonClient(address, clientConfig)
|
|
if err != nil {
|
|
return nil, errors.WithMessage(err, "failed to create OrdererClient from config")
|
|
}
|
|
return &OrdererClient{CommonClient: cc}, nil
|
|
}
|
|
|
|
// BroadcastOrdererClient describes a broadcast client
|
|
type BroadcastOrdererClient interface {
|
|
CloseSend() error
|
|
Send(envelope *cb.Envelope) error
|
|
Recv() (*ab.BroadcastResponse, error)
|
|
}
|
|
|
|
// Broadcast returns a broadcast client for the AtomicBroadcast service
|
|
func (oc *OrdererClient) Broadcast() (BroadcastOrdererClient, error) {
|
|
return newMulticastBroadcastClient(oc.address, oc.CommonClient.clientConfig.Dial)
|
|
}
|
|
|
|
// Deliver returns a deliver client for the AtomicBroadcast service
|
|
func (oc *OrdererClient) Deliver() (ab.AtomicBroadcast_DeliverClient, error) {
|
|
conn, err := oc.CommonClient.clientConfig.Dial(oc.address)
|
|
if err != nil {
|
|
return nil, errors.WithMessagef(err, "orderer client failed to connect to %s", oc.address)
|
|
}
|
|
// TODO: check to see if we should actually handle error before returning
|
|
return ab.NewAtomicBroadcastClient(conn).Deliver(context.TODO())
|
|
}
|
|
|
|
// Certificate returns the TLS client certificate (if available)
|
|
func (oc *OrdererClient) Certificate() tls.Certificate {
|
|
return oc.CommonClient.Certificate()
|
|
}
|
|
|
|
type multicastBroadcastClient struct {
|
|
clients []ab.AtomicBroadcast_BroadcastClient
|
|
}
|
|
|
|
type dialer func(address string) (*grpc.ClientConn, error)
|
|
|
|
func newMulticastBroadcastClient(addressString string, dial dialer) (*multicastBroadcastClient, error) {
|
|
addresses := []string{addressString}
|
|
if strings.Contains(addressString, ",") {
|
|
addresses = strings.Split(addressString, ",")
|
|
}
|
|
|
|
mbc := &multicastBroadcastClient{}
|
|
|
|
for _, addr := range addresses {
|
|
conn, err := dial(addr)
|
|
if err != nil {
|
|
return nil, errors.WithMessage(err, fmt.Sprintf("orderer client failed to connect to %s", addr))
|
|
}
|
|
cl, err := ab.NewAtomicBroadcastClient(conn).Broadcast(context.TODO())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
mbc.clients = append(mbc.clients, cl)
|
|
}
|
|
return mbc, nil
|
|
}
|
|
|
|
func (m *multicastBroadcastClient) CloseSend() error {
|
|
for _, cl := range m.clients {
|
|
err := cl.CloseSend()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *multicastBroadcastClient) Send(envelope *cb.Envelope) error {
|
|
for _, cl := range m.clients {
|
|
err := cl.Send(envelope)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *multicastBroadcastClient) Recv() (*ab.BroadcastResponse, error) {
|
|
var resp *ab.BroadcastResponse
|
|
var err error
|
|
for _, cl := range m.clients {
|
|
resp, err = cl.Recv()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return resp, nil
|
|
}
|