code: func (c *Client) processMessage(data []byte) (msg *dnode.Message, fn interface{}, err error) {
  	// Call error handler.
  	defer func() {
  		if err != nil {
  			onError(err)
  		}
  	}()
  
  	msg = &dnode.Message{}
  
  	if err = json.Unmarshal(data, &msg); err != nil {
  		return nil, nil, err
  	}
  
  	sender := func(id uint64, args []interface{}) error {
  		// do not name the error variable to "err" here, it's a trap for
  		// shadowing variables
  		_, _, e := c.marshalAndSend(id, args)
  		return e
  	}
  
  	// Replace function placeholders with real functions.
  	if err := dnode.ParseCallbacks(msg, sender); err != nil {
  		return nil, nil, err
  	}
  
  	// Find the handler function. Method may be string or integer.
  	switch method := msg.Method.(type) {
  	case float64:
  		id := uint64(method)
  		callback := c.scrubber.GetCallback(id)
  		if callback == nil {
  			err = dnode.CallbackNotFoundError{
  				ID:   id,
  				Args: msg.Arguments,
  			}
  			return nil, nil, err
  		}
  
  		return msg, callback, nil
  	case string:
  		m, ok := c.LocalKite.handlers[method]
  		if !ok {
  			err = dnode.MethodNotFoundError{
  				Method: method,
  				Args:   msg.Arguments,
  			}
  			return nil, nil, err
  		}
  
  		return msg, m, nil
  	default:
  		return nil, nil, fmt.Errorf("Method is not string or integer: %+v (%T)", msg.Method, msg.Method)
  	}
  }
docs: // processMessage processes a single message and calls a handler or callback.