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  }