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 }