Writing a rocketchat client to watch channel, initial channel sub (golang)

error:

2025-12-01T01:46:17Z INF Starting RocketChat client channel=#webhook server=wss://chat.redacted.xyz
2025-12-01T01:46:17Z INF Connecting to WebSocket url=wss://chat.redacted.xyz/websocket
2025-12-01T01:46:17Z INF Connected to RocketChat WebSocket
2025-12-01T01:46:17Z INF > Sent Connect
2025-12-01T01:46:17Z INF > Sent token
2025-12-01T01:46:17Z INF Found room channel=#webhook roomId=692cdf069e6f87cec12c8654
2025-12-01T01:46:17Z INF > Sent room subscribe message
2025-12-01T01:46:17Z ERR WebSocket connection lost error="websocket: close 1002 (protocol error)"

code:

func connectAndListen() error {
	wsURL := strings.Replace(serverURL, "https://", "wss://", 1)
	wsURL = strings.Replace(wsURL, "http://", "ws://", 1)
	wsURL = wsURL + "/websocket"

	log.Info().Str("url", wsURL).Msg("Connecting to WebSocket")

	conn, _, err := websocket.DefaultDialer.Dial(wsURL, nil)
	if err != nil {
		return fmt.Errorf("failed to connect to websocket: %w", err)
	}
	defer conn.Close()

	log.Info().Msg("Connected to RocketChat WebSocket")

	// Send connect message
	if err := sendMessage(conn, Message{
		Msg:    "connect",
		ID:     "1",
		Method: "connect",
		Params: []interface{}{"1", false},
	}); err != nil {
		return fmt.Errorf("failed to send connect message: %w", err)
	}

	// Wait for connect response
	//time.Sleep(2000 * time.Millisecond)
	//time.Sleep(500 * time.Millisecond)

	log.Info().Msg("> Sent Connect")

	// Login with token
	if err := sendMessage(conn, Message{
		Msg:    "method",
		ID:     "2",
		Method: "login",
		Params: []interface{}{map[string]string{"resume": token}},
	}); err != nil {
		return fmt.Errorf("failed to send login message: %w", err)
	}

	log.Info().Msg("> Sent token")

	// Get room ID
	roomID, err := getRoomID(conn, channel)
	if err != nil {
		return fmt.Errorf("failed to get room ID: %w", err)
	}

	log.Info().Str("roomId", roomID).Str("channel", channel).Msg("Found room")

	// Subscribe to room messages
	if err := sendMessage(conn, Message{
		Msg:    "sub",
		ID:     "3",
		Method: "stream-room-messages",
		Params: []interface{}{roomID, false},
	}); err != nil {
		return fmt.Errorf("failed to subscribe to room: %w", err)
	}

	log.Info().Msg("> Sent room subscribe message")

	// Listen for messages
	for {
		_, message, err := conn.ReadMessage()
		if err != nil {
			log.Error().Err(err).Msg("WebSocket connection lost")

			mu.Lock()
			if reconnected {
				mu.Unlock()
				return fmt.Errorf("connection lost after reconnect attempt")
			}
			reconnected = true
			mu.Unlock()

			log.Info().Msg("Attempting to reconnect...")
			time.Sleep(2 * time.Second)

			// Close old connection
			conn.Close()

			// Try to reconnect
			return connectAndListen()
		}

		var msg Message
		if err := json.Unmarshal(message, &msg); err != nil {
			log.Debug().Str("raw", string(message)).Msg("Could not parse message")
			continue
		}

		// Handle ping/pong
		if msg.Msg == "ping" {
			if err := sendMessage(conn, Message{Msg: "pong"}); err != nil {
				log.Error().Err(err).Msg("Failed to send pong")
			}
			continue
		}

		// Handle changed messages (new messages in room)
		if msg.Msg == "changed" && len(msg.Fields) > 0 {
			if args, ok := msg.Fields["args"].([]interface{}); ok && len(args) > 0 {
				if msgData, ok := args[0].(map[string]interface{}); ok {
					logRoomMessage(msgData)
				}
			}
		}
	}
}

func sendMessage(conn *websocket.Conn, msg Message) error {
	data, err := json.Marshal(msg)
	if err != nil {
		return err
	}
	return conn.WriteMessage(websocket.TextMessage, data)
}

Read the docs:

:warning: Warning: Deprecated

The DDP methods outlined are deprecated. We are no longer actively testing or maintaining these methods, and their behavior may be unreliable or change without notice.

Use the REST API provided.

Note also. Your reply was again marked as spam.

Rapid copy & paste posts will get canned. Think carefully about how you post.

Try to resist banning me for this message as we all need some feedback from time to time. This technique of blocking a message the second it is posted and then not allowing that message to be edited is basically trolling the community. I may have posted too quickly, as sometimes happens I did figure out what to do not too long after posting. If I had access to the message I could have just deleted it. And before I figured it out I could have added more context, because after posting I’m still troubleshooting and would like to add additional detail so there is as much context as possible for anyone generous enough to help. But instead I had to just wait for you to give me a talking to that the original unrefined posting wasn’t pristine. Also I know the answer, yet you take the opportunity to tell me to read the docs, cause I can’t get in there to delete the message before you have the chance. I think perhaps the strategy of just locking things instantly could maybe use an adjustment, unless you just like the chance to bully people, and that’s your goal. As you wish I’ll take lots of time and hesitate before posting in the future as otherwise there’s a good chance you’ll lock the message for your chance to bully/troll me. A very uniquely run forum.

The blocks are automatic by the system, not me. I tried to advise so you don’t get blocked again.

Don’t shoot the messenger.

Also I know the answer

In that case you should have added a post to say so.

You have made zero indication of that fact. You just posted an error and nothing else, and I am not a mind reader.

I’m not “bullying” you. I just responded to your post as above with some facts.