code: def fetch(self, method, path, query=None, body=None, timeout=0, **kwargs):
          
          ret = None
          if not query: query = {}
          if not body: body = {}
          query.update(body) # body takes precedence
          body = query
  
          self.send_count += 1
          payload = self.get_fetch_request(method, path, body)
          attempts = 1
          max_attempts = self.attempts
          success = False
  
          while not success:
              kwargs['timeout'] = timeout
              try:
                  try:
                      if not self.connected: self.connect(path)
                      with self.wstimeout(**kwargs) as timeout:
                          kwargs['timeout'] = timeout
  
                          logger.debug('{} send {} attempt {}/{} with timeout {}'.format(
                              self.client_id,
                              payload.uuid,
                              attempts,
                              max_attempts,
                              timeout
                          ))
  
                          sent_bits = self.ws.send(payload.payload)
                          logger.debug('{} sent {} bytes'.format(self.client_id, sent_bits))
                          if sent_bits:
                              ret = self.fetch_response(payload, **kwargs)
                              if ret:
                                  success = True
  
                  except websocket.WebSocketConnectionClosedException as e:
                      self.ws.shutdown()
                      raise IOError("connection is not open but reported it was open: {}".format(e))
  
              except (IOError, TypeError) as e:
                  logger.debug('{} error on send attempt {}: {}'.format(self.client_id, attempts, e))
                  success = False
  
              finally:
                  if not success:
                      attempts += 1
                      if attempts > max_attempts:
                          raise
  
                      else:
                          timeout *= 2
                          if (attempts / max_attempts) > 0.50:
                              logger.debug(
                                  "{} closing and re-opening connection for next attempt".format(self.client_id)
                              )
                              self.close()
  
          return ret
docs: send a Message
  
          :param method: string, something like "POST" or "GET"
          :param path: string, the path part of a uri (eg, /foo/bar)
          :param body: dict, what you want to send to "method path"
          :param timeout: integer, how long to wait before failing trying to send