miguelgrinberg / flask-sock

Modern WebSocket support for Flask.
MIT License
272 stars 24 forks source link

Help! Why my echo demo isn't working? HTTP 403 #83

Closed byrzhm closed 2 months ago

byrzhm commented 2 months ago

Apologize ahead of time, I'm a web-dev beginner and I want to write an echo demo. But I encountered a problem.

Here is my demo project layout:

Screenshot 2024-05-28 at 17 12 15

Here is __init__.py

import os

from flask import Flask, render_template

def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_mapping(
        SECRET_KEY='dev',
    )

    if test_config is None:
        # load the instance config, if it exists, when not testing
        app.config.from_pyfile('config.py', silent=True)
    else:
        # load the test config if passed in
        app.config.from_mapping(test_config)

    # ensure the instance folder exists
    try:
        os.makedirs(app.instance_path)
    except OSError:
        pass

    @app.route('/')
    def index():
        return render_template('index.html')

    from . import serve
    app.register_blueprint(serve.bp)

    return app

And here is my serve.py

from flask import current_app, Blueprint
from flask_sock import Sock
import threading
import time

bp = Blueprint("websocket", __name__, url_prefix="/websocket")
sock = Sock(current_app)
queue = []

def echo():
    while True:
        if len(queue) > 0:
            data, ws = queue.pop(0)
            ws.send(data)
        print("echo daemon running...")
        time.sleep(1)

echo_worker = threading.Thread(target=echo, daemon=True)
echo_worker.start()

@sock.route('/echo', bp=bp)
def echo(ws):
    while True:
        data = ws.receive()
        queue.append((data, ws))

I use flask run --debug to run server and client.py to connect to the server.

#!/usr/bin/env python

import asyncio
import websockets

host = 'localhost'
port = '5000'

async def echo():
    uri = "ws://" + host + ':' + port + "/websocket/echo"
    async with websockets.connect(uri) as websocket:
        while True:
            message = input("Input a string: ")

            await websocket.send(message)
            print(f">>> {message}")

            receive = await websocket.recv()
            print(f"<<< {receive}")

if __name__ == "__main__":
    asyncio.run(echo())

But the client cannot connect to the server. Here is the error message.

Screenshot 2024-05-28 at 17 31 46

I think the static and templates folders are irrelevant.

miguelgrinberg commented 2 months ago

This is wrong:

sock = Sock(current_app)

The value of current_app is undefined in the global scope, this likely gives you an error.

You need to review how Flask extensions are set up. The Flask-Sock extension must be initialized in create_app().

byrzhm commented 2 months ago

I don't know what's going on. I changed the port from 5000 (default) to 1234, and then it works! 🤨

Here are my changes:

byrzhm commented 2 months ago

I tried another machine and used the 5000 default port, but it worked fine. 🤨

I think the reason may be that port 5000 of my original machine is occupied, but the program does not throw any exception or provide relevant information, which I find very strange. 🤨

miguelgrinberg commented 2 months ago

@byrzhm You have ignored what I told you above. You cannot use current_app in the global scope. If it works for you, then you are doing something that is non-standard. And the code above does not correctly initialize the Flask-Sock extension.

You may want to review your application and look for examples that show you the correct patterns to use, if you care at all.