github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/events/consumer/consumer.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package consumer
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"sync"
    23  	"time"
    24  
    25  	"golang.org/x/net/context"
    26  	"google.golang.org/grpc"
    27  
    28  	"github.com/hyperledger/fabric/core/comm"
    29  	ehpb "github.com/hyperledger/fabric/protos/peer"
    30  )
    31  
    32  //EventsClient holds the stream and adapter for consumer to work with
    33  type EventsClient struct {
    34  	sync.RWMutex
    35  	peerAddress string
    36  	regTimeout  time.Duration
    37  	stream      ehpb.Events_ChatClient
    38  	adapter     EventAdapter
    39  }
    40  
    41  //NewEventsClient Returns a new grpc.ClientConn to the configured local PEER.
    42  func NewEventsClient(peerAddress string, regTimeout time.Duration, adapter EventAdapter) (*EventsClient, error) {
    43  	var err error
    44  	if regTimeout < 100*time.Millisecond {
    45  		regTimeout = 100 * time.Millisecond
    46  		err = fmt.Errorf("regTimeout >= 0, setting to 100 msec")
    47  	} else if regTimeout > 60*time.Second {
    48  		regTimeout = 60 * time.Second
    49  		err = fmt.Errorf("regTimeout > 60, setting to 60 sec")
    50  	}
    51  	return &EventsClient{sync.RWMutex{}, peerAddress, regTimeout, nil, adapter}, err
    52  }
    53  
    54  //newEventsClientConnectionWithAddress Returns a new grpc.ClientConn to the configured local PEER.
    55  func newEventsClientConnectionWithAddress(peerAddress string) (*grpc.ClientConn, error) {
    56  	if comm.TLSEnabled() {
    57  		return comm.NewClientConnectionWithAddress(peerAddress, true, true, comm.InitTLSForPeer())
    58  	}
    59  	return comm.NewClientConnectionWithAddress(peerAddress, true, false, nil)
    60  }
    61  
    62  func (ec *EventsClient) send(emsg *ehpb.Event) error {
    63  	ec.Lock()
    64  	defer ec.Unlock()
    65  	return ec.stream.Send(emsg)
    66  }
    67  
    68  // RegisterAsync - registers interest in a event and doesn't wait for a response
    69  func (ec *EventsClient) RegisterAsync(ies []*ehpb.Interest) error {
    70  	emsg := &ehpb.Event{Event: &ehpb.Event_Register{Register: &ehpb.Register{Events: ies}}}
    71  	var err error
    72  	if err = ec.send(emsg); err != nil {
    73  		fmt.Printf("error on Register send %s\n", err)
    74  	}
    75  	return err
    76  }
    77  
    78  // register - registers interest in a event
    79  func (ec *EventsClient) register(ies []*ehpb.Interest) error {
    80  	var err error
    81  	if err = ec.RegisterAsync(ies); err != nil {
    82  		return err
    83  	}
    84  
    85  	regChan := make(chan struct{})
    86  	go func() {
    87  		defer close(regChan)
    88  		in, inerr := ec.stream.Recv()
    89  		if inerr != nil {
    90  			err = inerr
    91  			return
    92  		}
    93  		switch in.Event.(type) {
    94  		case *ehpb.Event_Register:
    95  		case nil:
    96  			err = fmt.Errorf("invalid nil object for register")
    97  		default:
    98  			err = fmt.Errorf("invalid registration object")
    99  		}
   100  	}()
   101  	select {
   102  	case <-regChan:
   103  	case <-time.After(ec.regTimeout):
   104  		err = fmt.Errorf("timeout waiting for registration")
   105  	}
   106  	return err
   107  }
   108  
   109  // UnregisterAsync - Unregisters interest in a event and doesn't wait for a response
   110  func (ec *EventsClient) UnregisterAsync(ies []*ehpb.Interest) error {
   111  	emsg := &ehpb.Event{Event: &ehpb.Event_Unregister{Unregister: &ehpb.Unregister{Events: ies}}}
   112  	var err error
   113  	if err = ec.send(emsg); err != nil {
   114  		err = fmt.Errorf("error on unregister send %s\n", err)
   115  	}
   116  
   117  	return err
   118  }
   119  
   120  // unregister - unregisters interest in a event
   121  func (ec *EventsClient) unregister(ies []*ehpb.Interest) error {
   122  	var err error
   123  	if err = ec.UnregisterAsync(ies); err != nil {
   124  		return err
   125  	}
   126  
   127  	regChan := make(chan struct{})
   128  	go func() {
   129  		defer close(regChan)
   130  		in, inerr := ec.stream.Recv()
   131  		if inerr != nil {
   132  			err = inerr
   133  			return
   134  		}
   135  		switch in.Event.(type) {
   136  		case *ehpb.Event_Unregister:
   137  		case nil:
   138  			err = fmt.Errorf("invalid nil object for unregister")
   139  		default:
   140  			err = fmt.Errorf("invalid unregistration object")
   141  		}
   142  	}()
   143  	select {
   144  	case <-regChan:
   145  	case <-time.After(ec.regTimeout):
   146  		err = fmt.Errorf("timeout waiting for unregistration")
   147  	}
   148  	return err
   149  }
   150  
   151  // Recv recieves next event - use when client has not called Start
   152  func (ec *EventsClient) Recv() (*ehpb.Event, error) {
   153  	in, err := ec.stream.Recv()
   154  	if err == io.EOF {
   155  		// read done.
   156  		if ec.adapter != nil {
   157  			ec.adapter.Disconnected(nil)
   158  		}
   159  		return nil, err
   160  	}
   161  	if err != nil {
   162  		if ec.adapter != nil {
   163  			ec.adapter.Disconnected(err)
   164  		}
   165  		return nil, err
   166  	}
   167  	return in, nil
   168  }
   169  func (ec *EventsClient) processEvents() error {
   170  	defer ec.stream.CloseSend()
   171  	for {
   172  		in, err := ec.stream.Recv()
   173  		if err == io.EOF {
   174  			// read done.
   175  			if ec.adapter != nil {
   176  				ec.adapter.Disconnected(nil)
   177  			}
   178  			return nil
   179  		}
   180  		if err != nil {
   181  			if ec.adapter != nil {
   182  				ec.adapter.Disconnected(err)
   183  			}
   184  			return err
   185  		}
   186  		if ec.adapter != nil {
   187  			cont, err := ec.adapter.Recv(in)
   188  			if !cont {
   189  				return err
   190  			}
   191  		}
   192  	}
   193  }
   194  
   195  //Start establishes connection with Event hub and registers interested events with it
   196  func (ec *EventsClient) Start() error {
   197  	conn, err := newEventsClientConnectionWithAddress(ec.peerAddress)
   198  	if err != nil {
   199  		return fmt.Errorf("Could not create client conn to %s", ec.peerAddress)
   200  	}
   201  
   202  	ies, err := ec.adapter.GetInterestedEvents()
   203  	if err != nil {
   204  		return fmt.Errorf("error getting interested events:%s", err)
   205  	}
   206  
   207  	if len(ies) == 0 {
   208  		return fmt.Errorf("must supply interested events")
   209  	}
   210  
   211  	serverClient := ehpb.NewEventsClient(conn)
   212  	ec.stream, err = serverClient.Chat(context.Background())
   213  	if err != nil {
   214  		return fmt.Errorf("Could not create client conn to %s", ec.peerAddress)
   215  	}
   216  
   217  	if err = ec.register(ies); err != nil {
   218  		return err
   219  	}
   220  
   221  	go ec.processEvents()
   222  
   223  	return nil
   224  }
   225  
   226  //Stop terminates connection with event hub
   227  func (ec *EventsClient) Stop() error {
   228  	if ec.stream == nil {
   229  		// in case the steam/chat server has not been established earlier, we assume that it's closed, successfully
   230  		return nil
   231  	}
   232  	return ec.stream.CloseSend()
   233  }