code: func (w *WebsocketSession) Recv() (string, error) {
  	// Return previously received messages if there is any.
  	if len(w.messages) > 0 {
  		msg := w.messages[0]
  		w.messages = w.messages[1:]
  		return msg, nil
  	}
  
  read_frame:
  	if atomic.LoadInt32(&w.closed) == 1 {
  		return "", ErrSessionClosed
  	}
  
  	// Read one SockJS frame.
  	_, buf, err := w.conn.ReadMessage()
  	if err != nil {
  		return "", err
  	}
  
  	if len(buf) == 0 {
  		return "", errors.New("unexpected empty message")
  	}
  
  	frameType := buf[0]
  	data := buf[1:]
  
  	switch frameType {
  	case 'o':
  		w.setState(sockjs.SessionActive)
  		goto read_frame
  	case 'a':
  		var messages []string
  		err = json.Unmarshal(data, &messages)
  		if err != nil {
  			return "", err
  		}
  		w.messages = append(w.messages, messages...)
  	case 'm':
  		var message string
  		err = json.Unmarshal(data, &message)
  		if err != nil {
  			return "", err
  		}
  		w.messages = append(w.messages, message)
  	case 'c':
  		w.setState(sockjs.SessionClosed)
  		return "", ErrSessionClosed
  	case 'h':
  		// TODO handle heartbeat
  		goto read_frame
  	default:
  		return "", errors.New("invalid frame type")
  	}
  
  	// Return first message in slice.
  	if len(w.messages) == 0 {
  		return "", errors.New("no message")
  	}
  	msg := w.messages[0]
  	w.messages = w.messages[1:]
  	return msg, nil
  }
docs: // Recv reads one text frame from session.