github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/net/service/service.go (about) 1 package service 2 3 import ( 4 "errors" 5 "fmt" 6 "sync" 7 8 msg "github.com/jbenet/go-ipfs/net/message" 9 u "github.com/jbenet/go-ipfs/util" 10 ctxc "github.com/jbenet/go-ipfs/util/ctxcloser" 11 12 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" 13 ) 14 15 var log = u.Logger("service") 16 17 // ErrNoResponse is returned by Service when a Request did not get a response, 18 // and no other error happened 19 var ErrNoResponse = errors.New("no response to request") 20 21 // Handler is an interface that objects must implement in order to handle 22 // a service's requests. 23 type Handler interface { 24 25 // HandleMessage receives an incoming message, and potentially returns 26 // a response message to send back. 27 HandleMessage(context.Context, msg.NetMessage) msg.NetMessage 28 } 29 30 // Sender interface for network services. 31 type Sender interface { 32 // SendMessage sends out a given message, without expecting a response. 33 SendMessage(ctx context.Context, m msg.NetMessage) error 34 35 // SendRequest sends out a given message, and awaits a response. 36 // Set Deadlines or cancellations in the context.Context you pass in. 37 SendRequest(ctx context.Context, m msg.NetMessage) (msg.NetMessage, error) 38 } 39 40 // Service is an interface for a net resource with both outgoing (sender) and 41 // incomig (SetHandler) requests. 42 type Service interface { 43 Sender 44 ctxc.ContextCloser 45 46 // GetPipe 47 GetPipe() *msg.Pipe 48 49 // SetHandler assigns the request Handler for this service. 50 SetHandler(Handler) 51 GetHandler() Handler 52 } 53 54 // Service is a networking component that protocols can use to multiplex 55 // messages over the same channel, and to issue + handle requests. 56 type service struct { 57 // Handler is the object registered to handle incoming requests. 58 Handler Handler 59 HandlerLock sync.RWMutex 60 61 // Requests are all the pending requests on this service. 62 Requests RequestMap 63 RequestsLock sync.RWMutex 64 65 // Message Pipe (connected to the outside world) 66 *msg.Pipe 67 ctxc.ContextCloser 68 } 69 70 // NewService creates a service object with given type ID and Handler 71 func NewService(ctx context.Context, h Handler) Service { 72 s := &service{ 73 Handler: h, 74 Requests: RequestMap{}, 75 Pipe: msg.NewPipe(10), 76 ContextCloser: ctxc.NewContextCloser(ctx, nil), 77 } 78 79 s.Children().Add(1) 80 go s.handleIncomingMessages() 81 return s 82 } 83 84 // GetPipe implements the mux.Protocol interface 85 func (s *service) GetPipe() *msg.Pipe { 86 return s.Pipe 87 } 88 89 // sendMessage sends a message out (actual leg work. SendMessage is to export w/o rid) 90 func (s *service) sendMessage(ctx context.Context, m msg.NetMessage, rid RequestID) error { 91 92 // serialize ServiceMessage wrapper 93 data, err := wrapData(m.Data(), rid) 94 if err != nil { 95 return err 96 } 97 98 // log.Debug("Service send message [to = %s]", m.Peer()) 99 100 // send message 101 m2 := msg.New(m.Peer(), data) 102 select { 103 case s.Outgoing <- m2: 104 case <-ctx.Done(): 105 return ctx.Err() 106 } 107 108 return nil 109 } 110 111 // SendMessage sends a message out 112 func (s *service) SendMessage(ctx context.Context, m msg.NetMessage) error { 113 return s.sendMessage(ctx, m, nil) 114 } 115 116 // SendRequest sends a request message out and awaits a response. 117 func (s *service) SendRequest(ctx context.Context, m msg.NetMessage) (msg.NetMessage, error) { 118 119 // check if we should bail given our contexts 120 select { 121 default: 122 case <-s.Closing(): 123 return nil, fmt.Errorf("service closed: %s", s.Context().Err()) 124 case <-ctx.Done(): 125 return nil, ctx.Err() 126 } 127 128 // create a request 129 r, err := NewRequest(m.Peer().ID()) 130 if err != nil { 131 return nil, err 132 } 133 134 // register Request 135 s.RequestsLock.Lock() 136 s.Requests[r.Key()] = r 137 s.RequestsLock.Unlock() 138 139 // defer deleting this request 140 defer func() { 141 s.RequestsLock.Lock() 142 delete(s.Requests, r.Key()) 143 s.RequestsLock.Unlock() 144 }() 145 146 // check if we should bail after waiting for mutex 147 select { 148 default: 149 case <-s.Closing(): 150 return nil, fmt.Errorf("service closed: %s", s.Context().Err()) 151 case <-ctx.Done(): 152 return nil, ctx.Err() 153 } 154 155 // Send message 156 s.sendMessage(ctx, m, r.ID) 157 158 // wait for response 159 m = nil 160 err = nil 161 select { 162 case m = <-r.Response: 163 case <-s.Closed(): 164 err = fmt.Errorf("service closed: %s", s.Context().Err()) 165 case <-ctx.Done(): 166 err = ctx.Err() 167 } 168 169 if m == nil { 170 return nil, ErrNoResponse 171 } 172 173 return m, err 174 } 175 176 // handleIncoming consumes the messages on the s.Incoming channel and 177 // routes them appropriately (to requests, or handler). 178 func (s *service) handleIncomingMessages() { 179 defer s.Children().Done() 180 181 for { 182 select { 183 case m, more := <-s.Incoming: 184 if !more { 185 return 186 } 187 s.Children().Add(1) 188 go s.handleIncomingMessage(m) 189 190 case <-s.Closing(): 191 return 192 } 193 } 194 } 195 196 func (s *service) handleIncomingMessage(m msg.NetMessage) { 197 defer s.Children().Done() 198 199 // unwrap the incoming message 200 data, rid, err := unwrapData(m.Data()) 201 if err != nil { 202 log.Errorf("service de-serializing error: %v", err) 203 return 204 } 205 206 m2 := msg.New(m.Peer(), data) 207 208 // if it's a request (or has no RequestID), handle it 209 if rid == nil || rid.IsRequest() { 210 handler := s.GetHandler() 211 if handler == nil { 212 log.Errorf("service dropped msg: %v", m) 213 return // no handler, drop it. 214 } 215 216 // should this be "go HandleMessage ... ?" 217 r1 := handler.HandleMessage(s.Context(), m2) 218 219 // if handler gave us a response, send it back out! 220 if r1 != nil { 221 err := s.sendMessage(s.Context(), r1, rid.Response()) 222 if err != nil { 223 log.Errorf("error sending response message: %v", err) 224 } 225 } 226 return 227 } 228 229 // Otherwise, it is a response. handle it. 230 if !rid.IsResponse() { 231 log.Errorf("RequestID should identify a response here.") 232 } 233 234 key := RequestKey(m.Peer().ID(), RequestID(rid)) 235 s.RequestsLock.RLock() 236 r, found := s.Requests[key] 237 s.RequestsLock.RUnlock() 238 239 if !found { 240 log.Errorf("no request key %v (timeout?)", []byte(key)) 241 return 242 } 243 244 select { 245 case r.Response <- m2: 246 case <-s.Closing(): 247 } 248 } 249 250 // SetHandler assigns the request Handler for this service. 251 func (s *service) SetHandler(h Handler) { 252 s.HandlerLock.Lock() 253 defer s.HandlerLock.Unlock() 254 s.Handler = h 255 } 256 257 // GetHandler returns the request Handler for this service. 258 func (s *service) GetHandler() Handler { 259 s.HandlerLock.RLock() 260 defer s.HandlerLock.RUnlock() 261 return s.Handler 262 }