ngrok / ngrok-python

Embed ngrok secure ingress into your Python apps with a single line of code.
https://ngrok.com
Apache License 2.0
103 stars 19 forks source link

Websocket Connection #108

Open RohitMidha23 opened 3 months ago

RohitMidha23 commented 3 months ago

I have a particular usecase where I am trying to send data from my JS front end to my Python backend via websockets, exposed through ngrok.

Python Server:

async def handler(websocket):
    while True:
        message = await websocket.recv()
        print(message)

async def main():
    # Start WebSocket server
    async with websockets.serve(handler, args.host, args.port):
        await asyncio.Future()  # run forever

if __name__ == "__main__":
    ngrok_tunnel = ngrok.forward(args.port, "tcp", authtoken_from_env=True)
    print(f"Ngrok tunnel established at {ngrok_tunnel.url()}")
    asyncio.run(main())

JS Front End:

import { useState, useRef, useEffect } from "react";

const Test = () => {
  const [text, setText] = useState("");
  const [isCreateEvent, setIsCreateEvent] = useState(false);
  const [socket, setSocket] = useState(null);

  useEffect(() => {
    const newSocket = new WebSocket("ws://5.tcp.eu.ngrok.io:12075");
    setSocket(newSocket);
  }, []);

  useEffect(() => {
    if (socket && socket.readyState === WebSocket.OPEN) {
      socket.on("message", (event) => {
        // Update the text state based on the message received
        console.log({ event });
        const data = JSON.parse(event.data);
        setText((prev) => `${prev}\n${data.data}`);
      });
    }
  }, [socket]);
  const startCreateEvent = () => {
    const event = { data: "1" };
    socket.send(JSON.stringify(event));
  };

  const stopCreateEvent = async () => {
    await socket.close();
    setSocket(null);
  };

  return (
    <div>
      <h1>Test Socket</h1>
      <textarea value={text} readOnly />
      <button onClick={startCreateEvent} disabled={isCreateEvent}>
        Start 
      </button>
      <button onClick={stopCreateEvent} disabled={!isCreateEvent}>
        Stop 
      </button>
    </div>
  );
};

export default Test;

Error, on connection:

Traceback (most recent call last):
  File "/Users/miniconda3/envs/venv/lib/python3.10/site-packages/websockets/legacy/server.py", line 236, in handler
    await self.ws_handler(self)
  File "/Users/Desktop/server.py", line 126, in handler
    message = await websocket.recv()
  File "/Users/miniconda3/envs/venv/lib/python3.10/site-packages/websockets/legacy/protocol.py", line 568, in recv
    await self.ensure_open()
  File "/Users//miniconda3/envs/venv/lib/python3.10/site-packages/websockets/legacy/protocol.py", line 948, in ensure_open
    raise self.connection_closed_exc()
websockets.exceptions.ConnectionClosedError: sent 1011 (internal error) keepalive ping timeout; no close frame received

Note that this doesn't occur when I don't use NGROK, leading me to believe there is some error in the way the port is being forwarded.

I've tried the same with tcp and http.

CK-Ward commented 3 months ago

Hi @RohitMidha23, thank you for your submission. We are looking into this and will post back here when we have an update.